Date: Wed, 2 Jan 2013 19:58:19 GMT From: svn-freebsd-gecko@chruetertee.ch To: freebsd-gecko@freebsd.org Subject: [SVN-Commit] r1130 - in trunk: Mk mail/thunderbird/files www/firefox/files www/seamonkey/files Message-ID: <201301021958.r02JwJ9p030209@trillian.chruetertee.ch>
next in thread | raw e-mail | index | archive | help
Author: jbeich Date: Wed Jan 2 19:58:18 2013 New Revision: 1130 Log: don't extract/use test_quota.[hc] from bundled sqlite3 on >= gecko18 Added: trunk/mail/thunderbird/files/patch-bug787804 trunk/www/firefox/files/patch-bug787804 trunk/www/seamonkey/files/patch-bug787804 Modified: trunk/Mk/bsd.gecko.mk Modified: trunk/Mk/bsd.gecko.mk ============================================================================== --- trunk/Mk/bsd.gecko.mk Wed Jan 2 19:58:06 2013 (r1129) +++ trunk/Mk/bsd.gecko.mk Wed Jan 2 19:58:18 2013 (r1130) @@ -606,6 +606,9 @@ sqlite_LIB_DEPENDS= sqlite3:${PORTSDIR}/databases/sqlite3 sqlite_MOZ_OPTIONS= --enable-system-sqlite +.if ${MOZILLA_VER:R:R} >= 20 || exists(${.CURDIR}/files/patch-bug787804) +sqlite_EXTRACT_AFTER_ARGS= --exclude mozilla*/db/sqlite3 +.endif vpx_LIB_DEPENDS= vpx:${PORTSDIR}/multimedia/libvpx vpx_MOZ_OPTIONS= --with-system-libvpx Added: trunk/mail/thunderbird/files/patch-bug787804 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ trunk/mail/thunderbird/files/patch-bug787804 Wed Jan 2 19:58:18 2013 (r1130) @@ -0,0 +1,3557 @@ +commit 74997f1 +Author: Jan Varga <jan.varga@gmail.com> +Date: Mon Dec 17 20:25:10 2012 +0100 + + Bug 787804 - Rewrite quota handling (eliminate test_quota.c). r=bent,asuth,vladan +--- + db/sqlite3/README.MOZILLA | 4 +- + db/sqlite3/src/sqlite.def | 1 + + db/sqlite3/src/test_quota.c | 2001 -------------------- + db/sqlite3/src/test_quota.h | 274 --- + dom/Makefile.in | 1 + + dom/dom-config.mk | 1 + + dom/file/FileStreamWrappers.cpp | 11 - + dom/file/LockedFile.cpp | 8 +- + dom/file/nsIFileStorage.h | 40 +- + dom/indexedDB/FileManager.cpp | 33 +- + dom/indexedDB/FileManager.h | 20 +- + dom/indexedDB/FileStream.cpp | 321 ---- + dom/indexedDB/FileStream.h | 140 -- + dom/indexedDB/IDBDatabase.cpp | 6 + + dom/indexedDB/IDBFactory.cpp | 28 +- + dom/indexedDB/IDBFactory.h | 8 +- + dom/indexedDB/IDBFileHandle.cpp | 25 +- + dom/indexedDB/IDBObjectStore.cpp | 10 +- + dom/indexedDB/IDBTransaction.cpp | 3 +- + dom/indexedDB/IndexedDatabaseInlines.h | 13 + + dom/indexedDB/IndexedDatabaseManager.cpp | 162 +- + dom/indexedDB/IndexedDatabaseManager.h | 11 +- + dom/indexedDB/Makefile.in | 2 - + dom/indexedDB/OpenDatabaseHelper.cpp | 104 +- + dom/indexedDB/OpenDatabaseHelper.h | 12 +- + dom/indexedDB/nsIStandardFileStream.idl | 60 - + dom/indexedDB/test/Makefile.in | 2 + + dom/indexedDB/test/file.js | 21 +- + dom/indexedDB/test/test_file_quota.html | 14 +- + dom/indexedDB/test/test_filehandle_quota.html | 5 +- + dom/quota/FileStreams.cpp | 123 ++ + dom/quota/FileStreams.h | 115 ++ + dom/quota/Makefile.in | 33 + + dom/quota/QuotaCommon.h | 23 + + dom/quota/QuotaManager.cpp | 294 +++ + dom/quota/QuotaManager.h | 147 ++ + layout/build/Makefile.in | 1 + + netwerk/base/src/Makefile.in | 1 + + netwerk/base/src/nsFileStreams.cpp | 103 +- + netwerk/base/src/nsFileStreams.h | 12 +- + storage/public/Makefile.in | 1 - + storage/public/mozIStorageService.idl | 13 +- + .../public/mozIStorageServiceQuotaManagement.idl | 99 - + storage/public/storage.h | 1 - + storage/src/TelemetryVFS.cpp | 35 +- + storage/src/mozStorageConnection.cpp | 85 +- + storage/src/mozStorageConnection.h | 27 +- + storage/src/mozStorageService.cpp | 168 +- + storage/src/mozStorageService.h | 3 - + toolkit/toolkit-makefiles.sh | 1 + + 50 files changed, 1239 insertions(+), 3387 deletions(-) + +diff --git dom/Makefile.in dom/Makefile.in +index 672e065..47cd253 100644 +--- mozilla/dom/Makefile.in ++++ mozilla/dom/Makefile.in +@@ -58,6 +58,7 @@ PARALLEL_DIRS += \ + media \ + messages \ + power \ ++ quota \ + settings \ + sms \ + mms \ +diff --git dom/dom-config.mk dom/dom-config.mk +index d0f46cc..1cf57ed 100644 +--- mozilla/dom/dom-config.mk ++++ mozilla/dom/dom-config.mk +@@ -8,6 +8,7 @@ DOM_SRCDIRS = \ + dom/encoding \ + dom/file \ + dom/power \ ++ dom/quota \ + dom/media \ + dom/network/src \ + dom/settings \ +diff --git dom/file/FileStreamWrappers.cpp dom/file/FileStreamWrappers.cpp +index 2283266..c4cf102 100644 +--- mozilla/dom/file/FileStreamWrappers.cpp ++++ mozilla/dom/file/FileStreamWrappers.cpp +@@ -8,7 +8,6 @@ + + #include "nsIFileStorage.h" + #include "nsISeekableStream.h" +-#include "nsIStandardFileStream.h" + #include "mozilla/Attributes.h" + + #include "FileHelper.h" +@@ -246,16 +245,6 @@ FileOutputStreamWrapper::Close() + nsresult rv = NS_OK; + + if (!mFirstTime) { +- // We must flush buffers of the stream on the same thread on which we wrote +- // some data. +- nsCOMPtr<nsIStandardFileStream> sstream = do_QueryInterface(mFileStream); +- if (sstream) { +- rv = sstream->FlushBuffers(); +- if (NS_FAILED(rv)) { +- NS_WARNING("Failed to flush buffers of the stream!"); +- } +- } +- + NS_ASSERTION(PR_GetCurrentThread() == mWriteThread, + "Unsetting thread locals on wrong thread!"); + mFileHelper->mFileStorage->UnsetThreadLocals(); +diff --git dom/file/LockedFile.cpp dom/file/LockedFile.cpp +index 0fca730..926df91 100644 +--- mozilla/dom/file/LockedFile.cpp ++++ mozilla/dom/file/LockedFile.cpp +@@ -953,10 +953,10 @@ FinishHelper::Run() + } + + for (uint32_t index = 0; index < mParallelStreams.Length(); index++) { +- nsCOMPtr<nsIOutputStream> ostream = ++ nsCOMPtr<nsIInputStream> stream = + do_QueryInterface(mParallelStreams[index]); + +- if (NS_FAILED(ostream->Close())) { ++ if (NS_FAILED(stream->Close())) { + NS_WARNING("Failed to close stream!"); + } + +@@ -964,9 +964,9 @@ FinishHelper::Run() + } + + if (mStream) { +- nsCOMPtr<nsIOutputStream> ostream = do_QueryInterface(mStream); ++ nsCOMPtr<nsIInputStream> stream = do_QueryInterface(mStream); + +- if (NS_FAILED(ostream->Close())) { ++ if (NS_FAILED(stream->Close())) { + NS_WARNING("Failed to close stream!"); + } + +diff --git dom/file/nsIFileStorage.h dom/file/nsIFileStorage.h +index 92bb608..e985f0a 100644 +--- mozilla/dom/file/nsIFileStorage.h ++++ mozilla/dom/file/nsIFileStorage.h +@@ -10,14 +10,17 @@ + #include "nsISupports.h" + + #define NS_FILESTORAGE_IID \ +- {0xbba9c2ff, 0x85c9, 0x47c1, \ +- { 0xaf, 0xce, 0x0a, 0x7e, 0x6f, 0x21, 0x50, 0x95 } } ++ {0xa0801944, 0x2f1c, 0x4203, \ ++ { 0x9c, 0xaa, 0xaa, 0x47, 0xe0, 0x0c, 0x67, 0x92 } } + + class nsIFileStorage : public nsISupports + { + public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_FILESTORAGE_IID) + ++ virtual const nsACString& ++ StorageOrigin() = 0; ++ + virtual nsISupports* + StorageId() = 0; + +@@ -36,20 +39,23 @@ public: + + NS_DEFINE_STATIC_IID_ACCESSOR(nsIFileStorage, NS_FILESTORAGE_IID) + +-#define NS_DECL_NSIFILESTORAGE \ +- virtual nsISupports* \ +- StorageId(); \ +- \ +- virtual bool \ +- IsStorageInvalidated(); \ +- \ +- virtual bool \ +- IsStorageShuttingDown(); \ +- \ +- virtual void \ +- SetThreadLocals(); \ +- \ +- virtual void \ +- UnsetThreadLocals(); ++#define NS_DECL_NSIFILESTORAGE \ ++ virtual const nsACString& \ ++ StorageOrigin() MOZ_OVERRIDE; \ ++ \ ++ virtual nsISupports* \ ++ StorageId() MOZ_OVERRIDE; \ ++ \ ++ virtual bool \ ++ IsStorageInvalidated() MOZ_OVERRIDE; \ ++ \ ++ virtual bool \ ++ IsStorageShuttingDown() MOZ_OVERRIDE; \ ++ \ ++ virtual void \ ++ SetThreadLocals() MOZ_OVERRIDE; \ ++ \ ++ virtual void \ ++ UnsetThreadLocals() MOZ_OVERRIDE; + + #endif // nsIFileStorage_h__ +diff --git dom/indexedDB/FileManager.cpp dom/indexedDB/FileManager.cpp +index 9db56e8..4ed6e9e 100644 +--- mozilla/dom/indexedDB/FileManager.cpp ++++ mozilla/dom/indexedDB/FileManager.cpp +@@ -7,8 +7,8 @@ + #include "FileManager.h" + + #include "mozIStorageConnection.h" +-#include "mozIStorageServiceQuotaManagement.h" + #include "mozIStorageStatement.h" ++#include "nsIInputStream.h" + #include "nsISimpleEnumerator.h" + + #include "mozStorageCID.h" +@@ -18,6 +18,8 @@ + #include "IndexedDatabaseManager.h" + #include "OpenDatabaseHelper.h" + ++#include "IndexedDatabaseInlines.h" ++ + #define JOURNAL_DIRECTORY_NAME "journals" + + USING_INDEXEDDB_NAMESPACE +@@ -262,13 +264,11 @@ FileManager::GetFileForId(nsIFile* aDirectory, int64_t aId) + + // static + nsresult +-FileManager::InitDirectory(mozIStorageServiceQuotaManagement* aService, +- nsIFile* aDirectory, ++FileManager::InitDirectory(nsIFile* aDirectory, + nsIFile* aDatabaseFile, +- FactoryPrivilege aPrivilege) ++ const nsACString& aOrigin) + { + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); +- NS_ASSERTION(aService, "Null service!"); + NS_ASSERTION(aDirectory, "Null directory!"); + NS_ASSERTION(aDatabaseFile, "Null database file!"); + +@@ -310,8 +310,8 @@ FileManager::InitDirectory(mozIStorageServiceQuotaManagement* aService, + + if (hasElements) { + nsCOMPtr<mozIStorageConnection> connection; +- rv = OpenDatabaseHelper::CreateDatabaseConnection( +- NullString(), aDatabaseFile, aDirectory, getter_AddRefs(connection)); ++ rv = OpenDatabaseHelper::CreateDatabaseConnection(aDatabaseFile, ++ aDirectory, NullString(), aOrigin, getter_AddRefs(connection)); + NS_ENSURE_SUCCESS(rv, rv); + + mozStorageTransaction transaction(connection, false); +@@ -377,12 +377,17 @@ FileManager::InitDirectory(mozIStorageServiceQuotaManagement* aService, + } + } + +- if (aPrivilege == Chrome) { +- return NS_OK; +- } ++ return NS_OK; ++} ++ ++// static ++nsresult ++FileManager::GetUsage(nsIFile* aDirectory, uint64_t* aUsage) ++{ ++ uint64_t usage = 0; + + nsCOMPtr<nsISimpleEnumerator> entries; +- rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries)); ++ nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries)); + NS_ENSURE_SUCCESS(rv, rv); + + bool hasMore; +@@ -402,9 +407,13 @@ FileManager::InitDirectory(mozIStorageServiceQuotaManagement* aService, + continue; + } + +- rv = aService->UpdateQuotaInformationForFile(file); ++ int64_t fileSize; ++ rv = file->GetFileSize(&fileSize); + NS_ENSURE_SUCCESS(rv, rv); ++ ++ IncrementUsage(&usage, uint64_t(fileSize)); + } + ++ *aUsage = usage; + return NS_OK; + } +diff --git dom/indexedDB/FileManager.h dom/indexedDB/FileManager.h +index 2c72d0a..370d4a8 100644 +--- mozilla/dom/indexedDB/FileManager.h ++++ mozilla/dom/indexedDB/FileManager.h +@@ -24,10 +24,10 @@ class FileManager + friend class FileInfo; + + public: +- FileManager(const nsACString& aOrigin, ++ FileManager(const nsACString& aOrigin, FactoryPrivilege aPrivilege, + const nsAString& aDatabaseName) +- : mOrigin(aOrigin), mDatabaseName(aDatabaseName), mLastFileId(0), +- mInvalidated(false) ++ : mOrigin(aOrigin), mPrivilege(aPrivilege), mDatabaseName(aDatabaseName), ++ mLastFileId(0), mInvalidated(false) + { } + + ~FileManager() +@@ -40,6 +40,11 @@ public: + return mOrigin; + } + ++ const FactoryPrivilege& Privilege() const ++ { ++ return mPrivilege; ++ } ++ + const nsAString& DatabaseName() const + { + return mDatabaseName; +@@ -68,12 +73,15 @@ public: + static already_AddRefed<nsIFile> GetFileForId(nsIFile* aDirectory, + int64_t aId); + +- static nsresult InitDirectory(mozIStorageServiceQuotaManagement* aService, +- nsIFile* aDirectory, nsIFile* aDatabaseFile, +- FactoryPrivilege aPrivilege); ++ static nsresult InitDirectory(nsIFile* aDirectory, ++ nsIFile* aDatabaseFile, ++ const nsACString& aOrigin); ++ ++ static nsresult GetUsage(nsIFile* aDirectory, uint64_t* aUsage); + + private: + nsCString mOrigin; ++ FactoryPrivilege mPrivilege; + nsString mDatabaseName; + + nsString mDirectoryPath; +diff --git dom/indexedDB/FileStream.cpp dom/indexedDB/FileStream.cpp +deleted file mode 100644 +index dddf5d5..0000000 +--- mozilla/dom/indexedDB/FileStream.cpp ++++ /dev/null +@@ -1,321 +0,0 @@ +-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +-/* vim: set ts=2 et sw=2 tw=80: */ +-/* This Source Code Form is subject to the terms of the Mozilla Public +- * License, v. 2.0. If a copy of the MPL was not distributed with this file, +- * You can obtain one at http://mozilla.org/MPL/2.0/. */ +- +-#include "FileStream.h" +- +-#include "nsIFile.h" +- +-#include "nsThreadUtils.h" +-#include "test_quota.h" +- +-USING_INDEXEDDB_NAMESPACE +- +-NS_IMPL_THREADSAFE_ADDREF(FileStream) +-NS_IMPL_THREADSAFE_RELEASE(FileStream) +- +-NS_INTERFACE_MAP_BEGIN(FileStream) +- NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStandardFileStream) +- NS_INTERFACE_MAP_ENTRY(nsISeekableStream) +- NS_INTERFACE_MAP_ENTRY(nsIInputStream) +- NS_INTERFACE_MAP_ENTRY(nsIOutputStream) +- NS_INTERFACE_MAP_ENTRY(nsIStandardFileStream) +- NS_INTERFACE_MAP_ENTRY(nsIFileMetadata) +-NS_INTERFACE_MAP_END +- +-NS_IMETHODIMP +-FileStream::Seek(int32_t aWhence, int64_t aOffset) +-{ +- // TODO: Add support for 64 bit file sizes, bug 752431 +- NS_ENSURE_TRUE(aOffset <= INT32_MAX, NS_ERROR_INVALID_ARG); +- +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- int whence; +- switch (aWhence) { +- case nsISeekableStream::NS_SEEK_SET: +- whence = SEEK_SET; +- break; +- case nsISeekableStream::NS_SEEK_CUR: +- whence = SEEK_CUR; +- break; +- case nsISeekableStream::NS_SEEK_END: +- whence = SEEK_END; +- break; +- default: +- return NS_ERROR_INVALID_ARG; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- int rc = sqlite3_quota_fseek(mQuotaFile, aOffset, whence); +- NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR); +- +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::Tell(int64_t* aResult) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- long rc = sqlite3_quota_ftell(mQuotaFile); +- NS_ENSURE_TRUE(rc >= 0, NS_BASE_STREAM_OSERROR); +- +- *aResult = rc; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::SetEOF() +-{ +- int64_t pos; +- nsresult rv = Tell(&pos); +- NS_ENSURE_SUCCESS(rv, rv); +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- int rc = sqlite3_quota_ftruncate(mQuotaFile, pos); +- NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR); +- +- return NS_OK; +-} +- +- +-NS_IMETHODIMP +-FileStream::Close() +-{ +- CleanUpOpen(); +- +- if (mQuotaFile) { +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- int rc = sqlite3_quota_fclose(mQuotaFile); +- mQuotaFile = nullptr; +- +- NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR); +- } +- +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::Available(uint64_t* aResult) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- long rc = sqlite3_quota_file_available(mQuotaFile); +- NS_ENSURE_TRUE(rc >= 0, NS_BASE_STREAM_OSERROR); +- +- *aResult = rc; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::Read(char* aBuf, uint32_t aCount, uint32_t* aResult) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- size_t bytesRead = sqlite3_quota_fread(aBuf, 1, aCount, mQuotaFile); +- if (bytesRead < aCount && sqlite3_quota_ferror(mQuotaFile)) { +- return NS_BASE_STREAM_OSERROR; +- } +- +- *aResult = bytesRead; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, +- uint32_t aCount, uint32_t* aResult) +-{ +- NS_NOTREACHED("Don't call me!"); +- return NS_ERROR_NOT_IMPLEMENTED; +-} +- +-NS_IMETHODIMP +-FileStream::IsNonBlocking(bool *aNonBlocking) +-{ +- *aNonBlocking = false; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::Write(const char* aBuf, uint32_t aCount, uint32_t *aResult) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- size_t bytesWritten = sqlite3_quota_fwrite(aBuf, 1, aCount, mQuotaFile); +- if (bytesWritten < aCount) { +- return NS_BASE_STREAM_OSERROR; +- } +- +- *aResult = bytesWritten; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::Flush() +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- int rc = sqlite3_quota_fflush(mQuotaFile, 1); +- NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR); +- +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::WriteFrom(nsIInputStream *inStr, uint32_t count, uint32_t *_retval) +-{ +- return NS_ERROR_NOT_IMPLEMENTED; +-} +- +-NS_IMETHODIMP +-FileStream::WriteSegments(nsReadSegmentFun reader, void * closure, uint32_t count, uint32_t *_retval) +-{ +- NS_NOTREACHED("Don't call me!"); +- return NS_ERROR_NOT_IMPLEMENTED; +-} +- +-NS_IMETHODIMP +-FileStream::Init(nsIFile* aFile, const nsAString& aMode, int32_t aFlags) +-{ +- NS_ASSERTION(!mQuotaFile && !mDeferredOpen, "Already initialized!"); +- +- nsresult rv = aFile->GetPath(mFilePath); +- NS_ENSURE_SUCCESS(rv, rv); +- +- mMode = aMode; +- mFlags = aFlags; +- +- if (mFlags & nsIStandardFileStream::FLAGS_DEFER_OPEN) { +- mDeferredOpen = true; +- return NS_OK; +- } +- +- return DoOpen(); +-} +- +-NS_IMETHODIMP +-FileStream::GetSize(int64_t* _retval) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- // TODO: Use sqlite3_quota_file_size() here, bug 760783 +- int64_t rc = sqlite3_quota_file_truesize(mQuotaFile); +- +- NS_ASSERTION(rc >= 0, "The file is not under quota management!"); +- +- *_retval = rc; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::GetLastModified(int64_t* _retval) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- time_t mtime; +- int rc = sqlite3_quota_file_mtime(mQuotaFile, &mtime); +- NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR); +- +- *_retval = mtime * PR_MSEC_PER_SEC; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::FlushBuffers() +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- int rc = sqlite3_quota_fflush(mQuotaFile, 0); +- NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR); +- +- return NS_OK; +-} +- +-nsresult +-FileStream::DoOpen() +-{ +- NS_ASSERTION(!mFilePath.IsEmpty(), "Must have a file path"); +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- quota_FILE* quotaFile = +- sqlite3_quota_fopen(NS_ConvertUTF16toUTF8(mFilePath).get(), +- NS_ConvertUTF16toUTF8(mMode).get()); +- +- CleanUpOpen(); +- +- if (!quotaFile) { +- return NS_BASE_STREAM_OSERROR; +- } +- +- mQuotaFile = quotaFile; +- +- return NS_OK; +-} +diff --git dom/indexedDB/FileStream.h dom/indexedDB/FileStream.h +deleted file mode 100644 +index 09648b1..0000000 +--- mozilla/dom/indexedDB/FileStream.h ++++ /dev/null +@@ -1,140 +0,0 @@ +-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +-/* vim: set ts=2 et sw=2 tw=80: */ +-/* This Source Code Form is subject to the terms of the Mozilla Public +- * License, v. 2.0. If a copy of the MPL was not distributed with this file, +- * You can obtain one at http://mozilla.org/MPL/2.0/. */ +- +-#ifndef mozilla_dom_indexeddb_filestream_h__ +-#define mozilla_dom_indexeddb_filestream_h__ +- +-#include "IndexedDatabase.h" +- +-#include "nsIFileStreams.h" +-#include "nsIInputStream.h" +-#include "nsIOutputStream.h" +-#include "nsISeekableStream.h" +-#include "nsIStandardFileStream.h" +- +-class nsIFile; +-struct quota_FILE; +- +-BEGIN_INDEXEDDB_NAMESPACE +- +-class FileStream : public nsISeekableStream, +- public nsIInputStream, +- public nsIOutputStream, +- public nsIStandardFileStream, +- public nsIFileMetadata +-{ +-public: +- FileStream() +- : mFlags(0), +- mDeferredOpen(false), +- mQuotaFile(nullptr) +- { } +- +- virtual ~FileStream() +- { +- Close(); +- } +- +- NS_DECL_ISUPPORTS +- NS_DECL_NSISEEKABLESTREAM +- NS_DECL_NSISTANDARDFILESTREAM +- NS_DECL_NSIFILEMETADATA +- +- // nsIInputStream +- NS_IMETHOD +- Close(); +- +- NS_IMETHOD +- Available(uint64_t* _retval); +- +- NS_IMETHOD +- Read(char* aBuf, uint32_t aCount, uint32_t* _retval); +- +- NS_IMETHOD +- ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, uint32_t aCount, +- uint32_t* _retval); +- +- NS_IMETHOD +- IsNonBlocking(bool* _retval); +- +- // nsIOutputStream +- +- // Close() already declared +- +- NS_IMETHOD +- Flush(); +- +- NS_IMETHOD +- Write(const char* aBuf, uint32_t aCount, uint32_t* _retval); +- +- NS_IMETHOD +- WriteFrom(nsIInputStream* aFromStream, uint32_t aCount, uint32_t* _retval); +- +- NS_IMETHOD +- WriteSegments(nsReadSegmentFun aReader, void* aClosure, uint32_t aCount, +- uint32_t* _retval); +- +- // IsNonBlocking() already declared +- +-protected: +- /** +- * Cleans up data prepared in Init. +- */ +- void +- CleanUpOpen() +- { +- mFilePath.Truncate(); +- mDeferredOpen = false; +- } +- +- /** +- * Open the file. This is called either from Init +- * or from DoPendingOpen (if FLAGS_DEFER_OPEN is used when initializing this +- * stream). The default behavior of DoOpen is to open the file and save the +- * file descriptor. +- */ +- virtual nsresult +- DoOpen(); +- +- /** +- * If there is a pending open, do it now. It's important for this to be +- * inlined since we do it in almost every stream API call. +- */ +- nsresult +- DoPendingOpen() +- { +- if (!mDeferredOpen) { +- return NS_OK; +- } +- +- return DoOpen(); +- } +- +- /** +- * Data we need to do an open. +- */ +- nsString mFilePath; +- nsString mMode; +- +- /** +- * Flags describing our behavior. See the IDL file for possible values. +- */ +- int32_t mFlags; +- +- /** +- * Whether we have a pending open (see FLAGS_DEFER_OPEN in the IDL file). +- */ +- bool mDeferredOpen; +- +- /** +- * File descriptor for opened file. +- */ +- quota_FILE* mQuotaFile; +-}; +- +-END_INDEXEDDB_NAMESPACE +- +-#endif // mozilla_dom_indexeddb_filestream_h__ +diff --git dom/indexedDB/IDBDatabase.cpp dom/indexedDB/IDBDatabase.cpp +index 63500b0..8842daf 100644 +--- mozilla/dom/indexedDB/IDBDatabase.cpp ++++ mozilla/dom/indexedDB/IDBDatabase.cpp +@@ -779,6 +779,12 @@ IDBDatabase::Close() + return NS_OK; + } + ++const nsACString& ++IDBDatabase::StorageOrigin() ++{ ++ return Origin(); ++} ++ + nsISupports* + IDBDatabase::StorageId() + { +diff --git dom/indexedDB/IDBFactory.cpp dom/indexedDB/IDBFactory.cpp +index 1007df1..c1f573e 100644 +--- mozilla/dom/indexedDB/IDBFactory.cpp ++++ mozilla/dom/indexedDB/IDBFactory.cpp +@@ -253,8 +253,26 @@ IDBFactory::Create(ContentParent* aContentParent, + } + + // static ++already_AddRefed<nsIFileURL> ++IDBFactory::GetDatabaseFileURL(nsIFile* aDatabaseFile, const nsACString& aOrigin) ++{ ++ nsCOMPtr<nsIURI> uri; ++ nsresult rv = NS_NewFileURI(getter_AddRefs(uri), aDatabaseFile); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ ++ nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(uri); ++ NS_ASSERTION(fileUrl, "This should always succeed!"); ++ ++ rv = fileUrl->SetQuery(NS_LITERAL_CSTRING("origin=") + aOrigin); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ ++ return fileUrl.forget(); ++} ++ ++// static + already_AddRefed<mozIStorageConnection> +-IDBFactory::GetConnection(const nsAString& aDatabaseFilePath) ++IDBFactory::GetConnection(const nsAString& aDatabaseFilePath, ++ const nsACString& aOrigin) + { + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); + NS_ASSERTION(StringEndsWith(aDatabaseFilePath, NS_LITERAL_STRING(".sqlite")), +@@ -271,13 +289,15 @@ IDBFactory::GetConnection(const nsAString& aDatabaseFilePath) + NS_ENSURE_SUCCESS(rv, nullptr); + NS_ENSURE_TRUE(exists, nullptr); + +- nsCOMPtr<mozIStorageServiceQuotaManagement> ss = ++ nsCOMPtr<nsIFileURL> dbFileUrl = GetDatabaseFileURL(dbFile, aOrigin); ++ NS_ENSURE_TRUE(dbFileUrl, nullptr); ++ ++ nsCOMPtr<mozIStorageService> ss = + do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID); + NS_ENSURE_TRUE(ss, nullptr); + + nsCOMPtr<mozIStorageConnection> connection; +- rv = ss->OpenDatabaseWithVFS(dbFile, NS_LITERAL_CSTRING("quota"), +- getter_AddRefs(connection)); ++ rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(connection)); + NS_ENSURE_SUCCESS(rv, nullptr); + + // Turn on foreign key constraints and recursive triggers. +diff --git dom/indexedDB/IDBFactory.h dom/indexedDB/IDBFactory.h +index d5461f7..49dad42 100644 +--- mozilla/dom/indexedDB/IDBFactory.h ++++ mozilla/dom/indexedDB/IDBFactory.h +@@ -15,6 +15,8 @@ + #include "nsCycleCollectionParticipant.h" + + class nsIAtom; ++class nsIFile; ++class nsIFileURL; + class nsPIDOMWindow; + + namespace mozilla { +@@ -75,8 +77,12 @@ public: + static nsresult Create(ContentParent* aContentParent, + IDBFactory** aFactory); + ++ static already_AddRefed<nsIFileURL> ++ GetDatabaseFileURL(nsIFile* aDatabaseFile, const nsACString& aOrigin); ++ + static already_AddRefed<mozIStorageConnection> +- GetConnection(const nsAString& aDatabaseFilePath); ++ GetConnection(const nsAString& aDatabaseFilePath, ++ const nsACString& aOrigin); + + static nsresult + LoadDatabaseInformation(mozIStorageConnection* aConnection, +diff --git dom/indexedDB/IDBFileHandle.cpp dom/indexedDB/IDBFileHandle.cpp +index e0340ff..f71fd56 100644 +--- mozilla/dom/indexedDB/IDBFileHandle.cpp ++++ mozilla/dom/indexedDB/IDBFileHandle.cpp +@@ -6,15 +6,14 @@ + + #include "IDBFileHandle.h" + +-#include "nsIStandardFileStream.h" +- + #include "mozilla/dom/file/File.h" ++#include "mozilla/dom/quota/FileStreams.h" + #include "nsDOMClassInfoID.h" + +-#include "FileStream.h" + #include "IDBDatabase.h" + + USING_INDEXEDDB_NAMESPACE ++USING_QUOTA_NAMESPACE + + namespace { + +@@ -68,22 +67,22 @@ IDBFileHandle::Create(IDBDatabase* aDatabase, + already_AddRefed<nsISupports> + IDBFileHandle::CreateStream(nsIFile* aFile, bool aReadOnly) + { +- nsRefPtr<FileStream> stream = new FileStream(); ++ const nsACString& origin = mFileStorage->StorageOrigin(); ++ ++ nsCOMPtr<nsISupports> result; + +- nsString streamMode; + if (aReadOnly) { +- streamMode.AssignLiteral("rb"); ++ nsRefPtr<FileInputStream> stream = FileInputStream::Create( ++ origin, aFile, -1, -1, nsIFileInputStream::DEFER_OPEN); ++ result = NS_ISUPPORTS_CAST(nsIFileInputStream*, stream); + } + else { +- streamMode.AssignLiteral("r+b"); ++ nsRefPtr<FileStream> stream = FileStream::Create( ++ origin, aFile, -1, -1, nsIFileStream::DEFER_OPEN); ++ result = NS_ISUPPORTS_CAST(nsIFileStream*, stream); + } ++ NS_ENSURE_TRUE(result, nullptr); + +- nsresult rv = stream->Init(aFile, streamMode, +- nsIStandardFileStream::FLAGS_DEFER_OPEN); +- NS_ENSURE_SUCCESS(rv, nullptr); +- +- nsCOMPtr<nsISupports> result = +- NS_ISUPPORTS_CAST(nsIStandardFileStream*, stream); + return result.forget(); + } + +diff --git dom/indexedDB/IDBObjectStore.cpp dom/indexedDB/IDBObjectStore.cpp +index 746d473..1f16d26 100644 +--- mozilla/dom/indexedDB/IDBObjectStore.cpp ++++ mozilla/dom/indexedDB/IDBObjectStore.cpp +@@ -17,6 +17,7 @@ + #include "mozilla/dom/ContentParent.h" + #include "mozilla/dom/StructuredCloneTags.h" + #include "mozilla/dom/ipc/Blob.h" ++#include "mozilla/dom/quota/FileStreams.h" + #include "mozilla/storage.h" + #include "nsContentUtils.h" + #include "nsDOMClassInfo.h" +@@ -27,10 +28,8 @@ + #include "nsServiceManagerUtils.h" + #include "nsThreadUtils.h" + #include "snappy/snappy.h" +-#include "test_quota.h" + + #include "AsyncConnectionHelper.h" +-#include "FileStream.h" + #include "IDBCursor.h" + #include "IDBEvents.h" + #include "IDBFileHandle.h" +@@ -51,6 +50,7 @@ + USING_INDEXEDDB_NAMESPACE + using namespace mozilla::dom; + using namespace mozilla::dom::indexedDB::ipc; ++using mozilla::dom::quota::FileOutputStream; + + namespace { + +@@ -2734,9 +2734,9 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection) + nativeFile = fileManager->GetFileForId(directory, id); + NS_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- nsRefPtr<FileStream> outputStream = new FileStream(); +- rv = outputStream->Init(nativeFile, NS_LITERAL_STRING("wb"), 0); +- NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); ++ nsRefPtr<FileOutputStream> outputStream = FileOutputStream::Create( ++ mObjectStore->Transaction()->Database()->Origin(), nativeFile); ++ NS_ENSURE_TRUE(outputStream, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + rv = CopyData(inputStream, outputStream); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); +diff --git dom/indexedDB/IDBTransaction.cpp dom/indexedDB/IDBTransaction.cpp +index fcef7cc..a5345e2 100644 +--- mozilla/dom/indexedDB/IDBTransaction.cpp ++++ mozilla/dom/indexedDB/IDBTransaction.cpp +@@ -352,7 +352,8 @@ IDBTransaction::GetOrCreateConnection(mozIStorageConnection** aResult) + + if (!mConnection) { + nsCOMPtr<mozIStorageConnection> connection = +- IDBFactory::GetConnection(mDatabase->FilePath()); ++ IDBFactory::GetConnection(mDatabase->FilePath(), ++ mDatabase->Origin()); + NS_ENSURE_TRUE(connection, NS_ERROR_FAILURE); + + nsresult rv; +diff --git dom/indexedDB/IndexedDatabaseInlines.h dom/indexedDB/IndexedDatabaseInlines.h +index 62e65d6..f27d60c 100644 +--- mozilla/dom/indexedDB/IndexedDatabaseInlines.h ++++ mozilla/dom/indexedDB/IndexedDatabaseInlines.h +@@ -79,4 +79,17 @@ AppendConditionClause(const nsACString& aColumnName, + aResult += NS_LITERAL_CSTRING(" :") + aArgName; + } + ++inline void ++IncrementUsage(uint64_t* aUsage, uint64_t aDelta) ++{ ++ // Watch for overflow! ++ if ((UINT64_MAX - *aUsage) < aDelta) { ++ NS_WARNING("Usage exceeds the maximum!"); ++ *aUsage = UINT64_MAX; ++ } ++ else { ++ *aUsage += aDelta; ++ } ++} ++ + END_INDEXEDDB_NAMESPACE +diff --git dom/indexedDB/IndexedDatabaseManager.cpp dom/indexedDB/IndexedDatabaseManager.cpp +index e4ad647..88f09da 100644 +--- mozilla/dom/indexedDB/IndexedDatabaseManager.cpp ++++ mozilla/dom/indexedDB/IndexedDatabaseManager.cpp +@@ -22,6 +22,7 @@ + #include "nsITimer.h" + + #include "mozilla/dom/file/FileService.h" ++#include "mozilla/dom/quota/QuotaManager.h" + #include "mozilla/dom/TabContext.h" + #include "mozilla/LazyIdleThread.h" + #include "mozilla/Preferences.h" +@@ -36,7 +37,6 @@ + #include "nsThreadUtils.h" + #include "nsXPCOM.h" + #include "nsXPCOMPrivate.h" +-#include "test_quota.h" + #include "xpcpublic.h" + + #include "AsyncConnectionHelper.h" +@@ -48,6 +48,8 @@ + #include "OpenDatabaseHelper.h" + #include "TransactionThreadPool.h" + ++#include "IndexedDatabaseInlines.h" ++ + // The amount of time, in milliseconds, that our IO thread will stay alive + // after the last event it processes. + #define DEFAULT_THREAD_TIMEOUT_MS 30000 +@@ -70,6 +72,7 @@ using namespace mozilla::services; + using namespace mozilla::dom; + using mozilla::Preferences; + using mozilla::dom::file::FileService; ++using mozilla::dom::quota::QuotaManager; + + static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID); + +@@ -103,29 +106,6 @@ GetDatabaseBaseFilename(const nsAString& aFilename, + return true; + } + +-class QuotaCallback MOZ_FINAL : public mozIStorageQuotaCallback +-{ +-public: +- NS_DECL_ISUPPORTS +- +- NS_IMETHOD +- QuotaExceeded(const nsACString& aFilename, +- int64_t aCurrentSizeLimit, +- int64_t aCurrentTotalSize, +- nsISupports* aUserData, +- int64_t* _retval) +- { +- if (IndexedDatabaseManager::QuotaIsLifted()) { +- *_retval = 0; +- return NS_OK; +- } +- +- return NS_ERROR_FAILURE; +- } +-}; +- +-NS_IMPL_THREADSAFE_ISUPPORTS1(QuotaCallback, mozIStorageQuotaCallback) +- + // Adds all databases in the hash to the given array. + template <class T> + PLDHashOperator +@@ -440,8 +420,8 @@ IndexedDatabaseManager::GetOrCreate() + NS_LITERAL_CSTRING("IndexedDB I/O"), + LazyIdleThread::ManualShutdown); + +- // We need one quota callback object to hand to SQLite. +- instance->mQuotaCallbackSingleton = new QuotaCallback(); ++ // Make sure that the quota manager is up. ++ NS_ENSURE_TRUE(QuotaManager::GetOrCreate(), nullptr); + + // Make a timer here to avoid potential failures later. We don't actually + // initialize the timer until shutdown. +@@ -996,37 +976,15 @@ IndexedDatabaseManager::EnsureOriginIsInitialized(const nsACString& aOrigin, + return NS_OK; + } + +- // First figure out the filename pattern we'll use. +- nsCOMPtr<nsIFile> patternFile; +- rv = directory->Clone(getter_AddRefs(patternFile)); +- NS_ENSURE_SUCCESS(rv, rv); +- +- rv = patternFile->Append(NS_LITERAL_STRING("*")); +- NS_ENSURE_SUCCESS(rv, rv); +- +- nsString pattern; +- rv = patternFile->GetPath(pattern); +- NS_ENSURE_SUCCESS(rv, rv); +- +- // Now tell SQLite to start tracking this pattern for content. +- nsCOMPtr<mozIStorageServiceQuotaManagement> ss = +- do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID); +- NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE); +- +- if (aPrivilege != Chrome) { +- rv = ss->SetQuotaForFilenamePattern(NS_ConvertUTF16toUTF8(pattern), +- GetIndexedDBQuotaMB() * 1024 * 1024, +- mQuotaCallbackSingleton, nullptr); +- NS_ENSURE_SUCCESS(rv, rv); +- } +- + // We need to see if there are any files in the directory already. If they + // are database files then we need to cleanup stored files (if it's needed) +- // and also tell SQLite about all of them. ++ // and also initialize the quota. + + nsAutoTArray<nsString, 20> subdirsToProcess; + nsAutoTArray<nsCOMPtr<nsIFile> , 20> unknownFiles; + ++ uint64_t usage = 0; ++ + nsTHashtable<nsStringHashKey> validSubdirs; + validSubdirs.Init(20); + +@@ -1068,20 +1026,28 @@ IndexedDatabaseManager::EnsureOriginIsInitialized(const nsACString& aOrigin, + continue; + } + +- nsCOMPtr<nsIFile> fileManagerDirectory; +- rv = directory->Clone(getter_AddRefs(fileManagerDirectory)); ++ nsCOMPtr<nsIFile> fmDirectory; ++ rv = directory->Clone(getter_AddRefs(fmDirectory)); + NS_ENSURE_SUCCESS(rv, rv); + +- rv = fileManagerDirectory->Append(dbBaseFilename); ++ rv = fmDirectory->Append(dbBaseFilename); + NS_ENSURE_SUCCESS(rv, rv); + +- rv = FileManager::InitDirectory(ss, fileManagerDirectory, file, +- aPrivilege); ++ rv = FileManager::InitDirectory(fmDirectory, file, aOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + if (aPrivilege != Chrome) { +- rv = ss->UpdateQuotaInformationForFile(file); ++ uint64_t fileUsage; ++ rv = FileManager::GetUsage(fmDirectory, &fileUsage); + NS_ENSURE_SUCCESS(rv, rv); ++ ++ IncrementUsage(&usage, fileUsage); ++ ++ int64_t fileSize; ++ rv = file->GetFileSize(&fileSize); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ IncrementUsage(&usage, uint64_t(fileSize)); + } + + validSubdirs.PutEntry(dbBaseFilename); +@@ -1117,12 +1083,39 @@ IndexedDatabaseManager::EnsureOriginIsInitialized(const nsACString& aOrigin, + } + } + ++ if (aPrivilege != Chrome) { ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ quotaManager->InitQuotaForOrigin(aOrigin, GetIndexedDBQuotaMB(), usage); ++ } ++ + mInitializedOrigins.AppendElement(aOrigin); + + NS_ADDREF(*aDirectory = directory); + return NS_OK; + } + ++void ++IndexedDatabaseManager::UninitializeOriginsByPattern( ++ const nsACString& aPattern) ++{ ++#ifdef DEBUG ++ { ++ bool correctThread; ++ NS_ASSERTION(NS_SUCCEEDED(mIOThread->IsOnCurrentThread(&correctThread)) && ++ correctThread, ++ "Running on the wrong thread!"); ++ } ++#endif ++ ++ for (int32_t i = mInitializedOrigins.Length() - 1; i >= 0; i--) { ++ if (PatternMatchesOrigin(aPattern, mInitializedOrigins[i])) { ++ mInitializedOrigins.RemoveElementAt(i); ++ } ++ } ++} ++ + bool + IndexedDatabaseManager::QuotaIsLiftedInternal() + { +@@ -1250,16 +1243,14 @@ IndexedDatabaseManager::GetFileManager(const nsACString& aOrigin, + } + + void +-IndexedDatabaseManager::AddFileManager(const nsACString& aOrigin, +- const nsAString& aDatabaseName, +- FileManager* aFileManager) ++IndexedDatabaseManager::AddFileManager(FileManager* aFileManager) + { + NS_ASSERTION(aFileManager, "Null file manager!"); + + nsTArray<nsRefPtr<FileManager> >* array; +- if (!mFileManagers.Get(aOrigin, &array)) { ++ if (!mFileManagers.Get(aFileManager->Origin(), &array)) { + array = new nsTArray<nsRefPtr<FileManager> >(); +- mFileManagers.Put(aOrigin, array); ++ mFileManagers.Put(aFileManager->Origin(), array); + } + + array->AppendElement(aFileManager); +@@ -1783,6 +1774,13 @@ OriginClearRunnable::DeleteFiles(IndexedDatabaseManager* aManager) + // correctly... + NS_ERROR("Failed to remove directory!"); + } ++ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ quotaManager->RemoveQuotaForPattern(mOriginOrPattern); ++ ++ aManager->UninitializeOriginsByPattern(mOriginOrPattern); + } + } + +@@ -1880,19 +1878,6 @@ IndexedDatabaseManager::AsyncUsageRunnable::Cancel() + } + } + +-inline void +-IncrementUsage(uint64_t* aUsage, uint64_t aDelta) +-{ +- // Watch for overflow! +- if ((INT64_MAX - *aUsage) <= aDelta) { +- NS_WARNING("Database sizes exceed max we can report!"); +- *aUsage = INT64_MAX; +- } +- else { +- *aUsage += aDelta; +- } +-} +- + nsresult + IndexedDatabaseManager::AsyncUsageRunnable::TakeShortcut() + { +@@ -2295,25 +2280,22 @@ IndexedDatabaseManager::AsyncDeleteFileRunnable::Run() + nsCOMPtr<nsIFile> file = mFileManager->GetFileForId(directory, mFileId); + NS_ENSURE_TRUE(file, NS_ERROR_FAILURE); + +- nsString filePath; +- nsresult rv = file->GetPath(filePath); +- NS_ENSURE_SUCCESS(rv, rv); ++ nsresult rv; ++ int64_t fileSize; + +- int rc = sqlite3_quota_remove(NS_ConvertUTF16toUTF8(filePath).get()); +- if (rc != SQLITE_OK) { +- NS_WARNING("Failed to delete stored file!"); +- return NS_ERROR_FAILURE; ++ if (mFileManager->Privilege() != Chrome) { ++ rv = file->GetFileSize(&fileSize); ++ NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); + } + +- // sqlite3_quota_remove won't actually remove anything if we're not tracking +- // the quota here. Manually remove the file if it exists. +- bool exists; +- rv = file->Exists(&exists); +- NS_ENSURE_SUCCESS(rv, rv); ++ rv = file->Remove(false); ++ NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); + +- if (exists) { +- rv = file->Remove(false); +- NS_ENSURE_SUCCESS(rv, rv); ++ if (mFileManager->Privilege() != Chrome) { ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ quotaManager->DecreaseUsageForOrigin(mFileManager->Origin(), fileSize); + } + + directory = mFileManager->GetJournalDirectory(); +diff --git dom/indexedDB/IndexedDatabaseManager.h dom/indexedDB/IndexedDatabaseManager.h +index f9fbbf2..1ea5425 100644 +--- mozilla/dom/indexedDB/IndexedDatabaseManager.h ++++ mozilla/dom/indexedDB/IndexedDatabaseManager.h +@@ -23,7 +23,6 @@ + + #define INDEXEDDB_MANAGER_CONTRACTID "@mozilla.org/dom/indexeddb/manager;1" + +-class mozIStorageQuotaCallback; + class nsIAtom; + class nsIFile; + class nsITimer; +@@ -134,6 +133,8 @@ public: + FactoryPrivilege aPrivilege, + nsIFile** aDirectory); + ++ void UninitializeOriginsByPattern(const nsACString& aPattern); ++ + // Determine if the quota is lifted for the Window the current thread is + // using. + static inline bool +@@ -172,9 +173,7 @@ public: + const nsAString& aDatabaseName); + + void +- AddFileManager(const nsACString& aOrigin, +- const nsAString& aDatabaseName, +- FileManager* aFileManager); ++ AddFileManager(FileManager* aFileManager); + + void InvalidateFileManagersForPattern(const nsACString& aPattern); + +@@ -502,10 +501,6 @@ private: + // A timer that gets activated at shutdown to ensure we close all databases. + nsCOMPtr<nsITimer> mShutdownTimer; + +- // A single threadsafe instance of our quota callback. Created on the main +- // thread during GetOrCreate(). +- nsCOMPtr<mozIStorageQuotaCallback> mQuotaCallbackSingleton; +- + // A list of all successfully initialized origins. This list isn't protected + // by any mutex but it is only ever touched on the IO thread. + nsTArray<nsCString> mInitializedOrigins; +diff --git dom/indexedDB/Makefile.in dom/indexedDB/Makefile.in +index fef0858..09d4853 100644 +--- mozilla/dom/indexedDB/Makefile.in ++++ mozilla/dom/indexedDB/Makefile.in +@@ -25,7 +25,6 @@ CPPSRCS = \ + DatabaseInfo.cpp \ + FileInfo.cpp \ + FileManager.cpp \ +- FileStream.cpp \ + IDBCursor.cpp \ + IDBDatabase.cpp \ + IDBEvents.cpp \ +@@ -93,7 +92,6 @@ XPIDLSRCS = \ + nsIIDBVersionChangeEvent.idl \ + nsIIDBOpenDBRequest.idl \ + nsIIndexedDatabaseManager.idl \ +- nsIStandardFileStream.idl \ + $(NULL) + + DIRS += ipc +diff --git dom/indexedDB/OpenDatabaseHelper.cpp dom/indexedDB/OpenDatabaseHelper.cpp +index e71cad4..4cd7f61 100644 +--- mozilla/dom/indexedDB/OpenDatabaseHelper.cpp ++++ mozilla/dom/indexedDB/OpenDatabaseHelper.cpp +@@ -8,11 +8,12 @@ + + #include "nsIFile.h" + ++#include "mozilla/dom/quota/QuotaManager.h" + #include "mozilla/storage.h" + #include "nsEscape.h" ++#include "nsNetUtil.h" + #include "nsThreadUtils.h" + #include "snappy/snappy.h" +-#include "test_quota.h" + + #include "nsIBFCacheEntry.h" + #include "IDBEvents.h" +@@ -21,6 +22,7 @@ + + using namespace mozilla; + USING_INDEXEDDB_NAMESPACE ++USING_QUOTA_NAMESPACE + + namespace { + +@@ -1632,15 +1634,15 @@ OpenDatabaseHelper::DoDatabaseWork() + rv = dbFile->GetPath(mDatabaseFilePath); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- nsCOMPtr<nsIFile> fileManagerDirectory; +- rv = dbDirectory->Clone(getter_AddRefs(fileManagerDirectory)); ++ nsCOMPtr<nsIFile> fmDirectory; ++ rv = dbDirectory->Clone(getter_AddRefs(fmDirectory)); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- rv = fileManagerDirectory->Append(filename); ++ rv = fmDirectory->Append(filename); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + nsCOMPtr<mozIStorageConnection> connection; +- rv = CreateDatabaseConnection(mName, dbFile, fileManagerDirectory, ++ rv = CreateDatabaseConnection(dbFile, fmDirectory, mName, mASCIIOrigin, + getter_AddRefs(connection)); + if (NS_FAILED(rv) && + NS_ERROR_GET_MODULE(rv) != NS_ERROR_MODULE_DOM_INDEXEDDB) { +@@ -1691,12 +1693,12 @@ OpenDatabaseHelper::DoDatabaseWork() + + nsRefPtr<FileManager> fileManager = mgr->GetFileManager(mASCIIOrigin, mName); + if (!fileManager) { +- fileManager = new FileManager(mASCIIOrigin, mName); ++ fileManager = new FileManager(mASCIIOrigin, mPrivilege, mName); + +- rv = fileManager->Init(fileManagerDirectory, connection); ++ rv = fileManager->Init(fmDirectory, connection); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- mgr->AddFileManager(mASCIIOrigin, mName, fileManager); ++ mgr->AddFileManager(fileManager); + } + + mFileManager = fileManager.forget(); +@@ -1707,23 +1709,26 @@ OpenDatabaseHelper::DoDatabaseWork() + // static + nsresult + OpenDatabaseHelper::CreateDatabaseConnection( +- const nsAString& aName, + nsIFile* aDBFile, +- nsIFile* aFileManagerDirectory, ++ nsIFile* aFMDirectory, ++ const nsAString& aName, ++ const nsACString& aOrigin, + mozIStorageConnection** aConnection) + { + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); + +- NS_NAMED_LITERAL_CSTRING(quotaVFSName, "quota"); ++ nsCOMPtr<nsIFileURL> dbFileUrl = ++ IDBFactory::GetDatabaseFileURL(aDBFile, aOrigin); ++ NS_ENSURE_TRUE(dbFileUrl, NS_ERROR_FAILURE); + +- nsCOMPtr<mozIStorageServiceQuotaManagement> ss = ++ nsCOMPtr<mozIStorageService> ss = + do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID); + NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE); + + nsCOMPtr<mozIStorageConnection> connection; +- nsresult rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName, +- getter_AddRefs(connection)); ++ nsresult rv = ++ ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(connection)); + if (rv == NS_ERROR_FILE_CORRUPTED) { + // If we're just opening the database during origin initialization, then + // we don't want to erase any files. The failure here will fail origin +@@ -1737,21 +1742,20 @@ OpenDatabaseHelper::CreateDatabaseConnection( + NS_ENSURE_SUCCESS(rv, rv); + + bool exists; +- rv = aFileManagerDirectory->Exists(&exists); ++ rv = aFMDirectory->Exists(&exists); + NS_ENSURE_SUCCESS(rv, rv); + + if (exists) { + bool isDirectory; +- rv = aFileManagerDirectory->IsDirectory(&isDirectory); ++ rv = aFMDirectory->IsDirectory(&isDirectory); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- rv = aFileManagerDirectory->Remove(true); ++ rv = aFMDirectory->Remove(true); + NS_ENSURE_SUCCESS(rv, rv); + } + +- rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName, +- getter_AddRefs(connection)); ++ rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(connection)); + } + NS_ENSURE_SUCCESS(rv, rv); + +@@ -2347,6 +2351,8 @@ DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection) + { + NS_ASSERTION(!aConnection, "How did we get a connection here?"); + ++ const FactoryPrivilege& privilege = mOpenHelper->Privilege(); ++ + IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); + NS_ASSERTION(mgr, "This should never fail!"); + +@@ -2372,59 +2378,57 @@ DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection) + rv = dbFile->Exists(&exists); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- int rc; +- + if (exists) { +- nsString dbFilePath; +- rv = dbFile->GetPath(dbFilePath); +- NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); ++ int64_t fileSize; + +- rc = sqlite3_quota_remove(NS_ConvertUTF16toUTF8(dbFilePath).get()); +- if (rc != SQLITE_OK) { +- NS_WARNING("Failed to delete db file!"); +- return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; ++ if (privilege != Chrome) { ++ rv = dbFile->GetFileSize(&fileSize); ++ NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + } + +- // sqlite3_quota_remove won't actually remove anything if we're not tracking +- // the quota here. Manually remove the file if it exists. +- rv = dbFile->Exists(&exists); ++ rv = dbFile->Remove(false); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- if (exists) { +- rv = dbFile->Remove(false); +- NS_ENSURE_SUCCESS(rv, rv); ++ if (privilege != Chrome) { ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ quotaManager->DecreaseUsageForOrigin(mASCIIOrigin, fileSize); + } + } + +- nsCOMPtr<nsIFile> fileManagerDirectory; +- rv = directory->Clone(getter_AddRefs(fileManagerDirectory)); +- NS_ENSURE_SUCCESS(rv, rv); ++ nsCOMPtr<nsIFile> fmDirectory; ++ rv = directory->Clone(getter_AddRefs(fmDirectory)); ++ NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- rv = fileManagerDirectory->Append(filename); ++ rv = fmDirectory->Append(filename); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- rv = fileManagerDirectory->Exists(&exists); ++ rv = fmDirectory->Exists(&exists); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + if (exists) { + bool isDirectory; +- rv = fileManagerDirectory->IsDirectory(&isDirectory); ++ rv = fmDirectory->IsDirectory(&isDirectory); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- nsString fileManagerDirectoryPath; +- rv = fileManagerDirectory->GetPath(fileManagerDirectoryPath); +- NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); ++ uint64_t usage = 0; + +- rc = sqlite3_quota_remove( +- NS_ConvertUTF16toUTF8(fileManagerDirectoryPath).get()); +- if (rc != SQLITE_OK) { +- NS_WARNING("Failed to delete file directory!"); +- return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; ++ if (privilege != Chrome) { ++ rv = FileManager::GetUsage(fmDirectory, &usage); ++ NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + } + +- rv = fileManagerDirectory->Remove(true); +- NS_ENSURE_SUCCESS(rv, rv); ++ rv = fmDirectory->Remove(true); ++ NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); ++ ++ if (privilege != Chrome) { ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ quotaManager->DecreaseUsageForOrigin(mASCIIOrigin, usage); ++ } + } + + return NS_OK; +diff --git dom/indexedDB/OpenDatabaseHelper.h dom/indexedDB/OpenDatabaseHelper.h +index 587301b..5a3d987 100644 +--- mozilla/dom/indexedDB/OpenDatabaseHelper.h ++++ mozilla/dom/indexedDB/OpenDatabaseHelper.h +@@ -77,10 +77,16 @@ public: + return mDatabase; + } + ++ const FactoryPrivilege& Privilege() const ++ { ++ return mPrivilege; ++ } ++ + static +- nsresult CreateDatabaseConnection(const nsAString& aName, +- nsIFile* aDBFile, +- nsIFile* aFileManagerDirectory, ++ nsresult CreateDatabaseConnection(nsIFile* aDBFile, ++ nsIFile* aFMDirectory, ++ const nsAString& aName, ++ const nsACString& aOrigin, + mozIStorageConnection** aConnection); + + protected: +diff --git dom/indexedDB/nsIStandardFileStream.idl dom/indexedDB/nsIStandardFileStream.idl +deleted file mode 100644 +index 265c3ed..0000000 +--- mozilla/dom/indexedDB/nsIStandardFileStream.idl ++++ /dev/null +@@ -1,60 +0,0 @@ +-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +-/* vim: set ts=2 et sw=2 tw=80: */ +-/* This Source Code Form is subject to the terms of the Mozilla Public +- * License, v. 2.0. If a copy of the MPL was not distributed with this file, +- * You can obtain one at http://mozilla.org/MPL/2.0/. */ +- +-#include "nsISupports.idl" +- +-interface nsIFile; +- +-/** +- * A stream that allows you to read from a file or stream to a file +- * using standard file APIs. +- */ +-[scriptable, uuid(ebbbb779-92a3-4b2a-b7cf-6efbe904c453)] +-interface nsIStandardFileStream : nsISupports +-{ +- /** +- * If this is set, the file will be opened (i.e., a call to +- * fopen done) only when we do an actual operation on the stream, +- * or more specifically, when one of the following is called: +- * - Seek +- * - Tell +- * - SetEOF +- * - Available +- * - Read +- * - Write +- * - Flush +- * - GetSize +- * - GetLastModified +- * - Sync +- * +- * FLAGS_DEFER_OPEN is useful if we use the stream on a background +- * thread, so that the opening and possible |stat|ing of the file +- * happens there as well. +- * +- * @note Using this flag results in the file not being opened +- * during the call to Init. This means that any errors that might +- * happen when this flag is not set would happen during the +- * first read. Also, the file is not locked when Init is called, +- * so it might be deleted before we try to read from it. +- */ +- const long FLAGS_DEFER_OPEN = 1 << 0; +- +- /** +- * @param file file to read from or stream to +- * @param mode file open mode (see fopen documentation) +- * @param flags flags specifying various behaviors of the class +- * (see enumerations in the class) +- */ +- void init(in nsIFile file, +- in AString mode, +- in long flags); +- +- /** +- * Flush all written content held in memory buffers out to disk. +- * This is the equivalent of fflush() +- */ +- void flushBuffers(); +-}; +diff --git dom/indexedDB/test/Makefile.in dom/indexedDB/test/Makefile.in +index 9c79b14..4c9a201 100644 +--- mozilla/dom/indexedDB/test/Makefile.in ++++ mozilla/dom/indexedDB/test/Makefile.in +@@ -54,11 +54,13 @@ MOCHITEST_FILES = \ + test_file_os_delete.html \ + test_file_put_get_object.html \ + test_file_put_get_values.html \ ++ test_file_quota.html \ + test_file_replace.html \ + test_file_resurrection_delete.html \ + test_file_resurrection_transaction_abort.html \ + test_file_sharing.html \ + test_file_transaction_abort.html \ ++ test_filehandle_quota.html \ + test_filehandle_serialization.html \ + test_filehandle_store_snapshot.html \ + test_getAll.html \ +diff --git dom/indexedDB/test/file.js dom/indexedDB/test/file.js +index 07bd10a..3c6194a 100644 +--- mozilla/dom/indexedDB/test/file.js ++++ mozilla/dom/indexedDB/test/file.js +@@ -3,6 +3,8 @@ + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + ++const DEFAULT_QUOTA = 50 * 1024 * 1024; ++ + var bufferCache = []; + var utils = SpecialPowers.getDOMWindowUtils(window); + +@@ -184,25 +186,6 @@ function getUsage(usageHandler) + idbManager.getUsageForURI(uri, callback); + } + +-function getUsageSync() +-{ +- let usage; +- +- getUsage(function(aUsage, aFileUsage) { +- usage = aUsage; +- }); +- +- let comp = SpecialPowers.wrap(Components); +- let thread = comp.classes["@mozilla.org/thread-manager;1"] +- .getService(comp.interfaces.nsIThreadManager) +- .currentThread; +- while (!usage) { +- thread.processNextEvent(true); +- } +- +- return usage; +-} +- + function scheduleGC() + { + SpecialPowers.exactGC(window, continueToNextStep); +diff --git dom/indexedDB/test/test_file_quota.html dom/indexedDB/test/test_file_quota.html +index b07880d..9fbc0c0 100644 +--- mozilla/dom/indexedDB/test/test_file_quota.html ++++ mozilla/dom/indexedDB/test/test_file_quota.html +@@ -13,14 +13,12 @@ + function testSteps() + { + const READ_WRITE = IDBTransaction.READ_WRITE; +- const DEFAULT_QUOTA_MB = 50; + + const name = window.location.pathname; + + const objectStoreName = "Blobs"; + +- const testData = { key: 0, value: {} }; +- const fileData = { key: 1, file: null }; ++ const fileData = { key: 1, file: getNullFile("random.bin", DEFAULT_QUOTA) }; + + let request = indexedDB.open(name, 1); + request.onerror = errorHandler; +@@ -32,21 +30,17 @@ + + let db = event.target.result; + +- let objectStore = db.createObjectStore(objectStoreName, { }); +- objectStore.add(testData.value, testData.key); +- +- let size = (DEFAULT_QUOTA_MB + 1) * 1024 * 1024 - getUsageSync(); +- fileData.file = getNullFile("random.bin", size); ++ db.createObjectStore(objectStoreName, { }); + + event = yield; + + is(event.type, "success", "Got correct event type"); + + trans = db.transaction([objectStoreName], READ_WRITE); +- objectStore = trans.objectStore(objectStoreName); ++ let objectStore = trans.objectStore(objectStoreName); + + request = objectStore.add(fileData.file, fileData.key); +- request.addEventListener("error", new ExpectError("UnknownError")); ++ request.addEventListener("error", new ExpectError("UnknownError", true)); + request.onsuccess = unexpectedSuccessHandler; + event = yield; + +diff --git dom/indexedDB/test/test_filehandle_quota.html dom/indexedDB/test/test_filehandle_quota.html +index addaf01..0506279 100644 +--- mozilla/dom/indexedDB/test/test_filehandle_quota.html ++++ mozilla/dom/indexedDB/test/test_filehandle_quota.html +@@ -13,7 +13,6 @@ + function testSteps() + { + const READ_WRITE = IDBTransaction.READ_WRITE; +- const DEFAULT_QUOTA_MB = 50; + + const name = window.location.pathname; + +@@ -39,10 +38,10 @@ + + let lockedFile = fileHandle.open("readwrite"); + +- let blob = getNullBlob((50 + 1) * 1024 * 1024 - getUsageSync()); ++ let blob = getNullBlob(DEFAULT_QUOTA); + + request = lockedFile.write(blob); +- request.addEventListener("error", new ExpectError("UnknownError")); ++ request.addEventListener("error", new ExpectError("UnknownError", true)); + request.onsuccess = unexpectedSuccessHandler; + event = yield; + +diff --git dom/quota/FileStreams.cpp dom/quota/FileStreams.cpp +new file mode 100644 +index 0000000..9de244f +--- /dev/null ++++ mozilla/dom/quota/FileStreams.cpp +@@ -0,0 +1,123 @@ ++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* vim: set ts=2 et sw=2 tw=80: */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#include "FileStreams.h" ++ ++USING_QUOTA_NAMESPACE ++ ++template <class FileStreamBase> ++NS_IMETHODIMP ++FileQuotaStream<FileStreamBase>::SetEOF() ++{ ++ nsresult rv = FileStreamBase::SetEOF(); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ if (mQuotaObject) { ++ int64_t offset; ++ nsresult rv = FileStreamBase::Tell(&offset); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ mQuotaObject->UpdateSize(offset); ++ } ++ ++ return NS_OK; ++} ++ ++template <class FileStreamBase> ++NS_IMETHODIMP ++FileQuotaStream<FileStreamBase>::Close() ++{ ++ nsresult rv = FileStreamBase::Close(); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ mQuotaObject = nullptr; ++ ++ return NS_OK; ++} ++ ++template <class FileStreamBase> ++nsresult ++FileQuotaStream<FileStreamBase>::DoOpen() ++{ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ NS_ASSERTION(!mQuotaObject, "Creating quota object more than once?"); ++ mQuotaObject = quotaManager->GetQuotaObject(mOrigin, ++ FileStreamBase::mOpenParams.localFile); ++ ++ nsresult rv = FileStreamBase::DoOpen(); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ if (mQuotaObject && (FileStreamBase::mOpenParams.ioFlags & PR_TRUNCATE)) { ++ mQuotaObject->UpdateSize(0); ++ } ++ ++ return NS_OK; ++} ++ ++template <class FileStreamBase> ++NS_IMETHODIMP ++FileQuotaStreamWithWrite<FileStreamBase>::Write(const char* aBuf, ++ uint32_t aCount, ++ uint32_t* _retval) ++{ ++ nsresult rv; ++ ++ if (FileQuotaStreamWithWrite::mQuotaObject) { ++ int64_t offset; ++ rv = FileStreamBase::Tell(&offset); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ if (!FileQuotaStreamWithWrite:: ++ mQuotaObject->MaybeAllocateMoreSpace(offset, aCount)) { ++ return NS_ERROR_FAILURE; ++ } ++ } ++ ++ rv = FileStreamBase::Write(aBuf, aCount, _retval); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ return NS_OK; ++} ++ ++NS_IMPL_ISUPPORTS_INHERITED0(FileInputStream, nsFileInputStream) ++ ++already_AddRefed<FileInputStream> ++FileInputStream::Create(const nsACString& aOrigin, nsIFile* aFile, ++ int32_t aIOFlags, int32_t aPerm, ++ int32_t aBehaviorFlags) ++{ ++ nsRefPtr<FileInputStream> stream = new FileInputStream(aOrigin); ++ nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ return stream.forget(); ++} ++ ++NS_IMPL_ISUPPORTS_INHERITED0(FileOutputStream, nsFileOutputStream) ++ ++already_AddRefed<FileOutputStream> ++FileOutputStream::Create(const nsACString& aOrigin, nsIFile* aFile, ++ int32_t aIOFlags, int32_t aPerm, ++ int32_t aBehaviorFlags) ++{ ++ nsRefPtr<FileOutputStream> stream = new FileOutputStream(aOrigin); ++ nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ return stream.forget(); ++} ++ ++NS_IMPL_ISUPPORTS_INHERITED0(FileStream, nsFileStream) ++ ++already_AddRefed<FileStream> ++FileStream::Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags, ++ int32_t aPerm, int32_t aBehaviorFlags) ++{ ++ nsRefPtr<FileStream> stream = new FileStream(aOrigin); ++ nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ return stream.forget(); ++} +diff --git dom/quota/FileStreams.h dom/quota/FileStreams.h +new file mode 100644 +index 0000000..77bfad4 +--- /dev/null ++++ mozilla/dom/quota/FileStreams.h +@@ -0,0 +1,115 @@ ++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* vim: set ts=2 et sw=2 tw=80: */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#ifndef mozilla_dom_quota_filestreams_h__ ++#define mozilla_dom_quota_filestreams_h__ ++ ++#include "QuotaCommon.h" ++ ++#include "nsFileStreams.h" ++ ++#include "QuotaManager.h" ++ ++BEGIN_QUOTA_NAMESPACE ++ ++template <class FileStreamBase> ++class FileQuotaStream : public FileStreamBase ++{ ++public: ++ // nsFileStreamBase override ++ NS_IMETHOD ++ SetEOF() MOZ_OVERRIDE; ++ ++ NS_IMETHOD ++ Close() MOZ_OVERRIDE; ++ ++protected: ++ FileQuotaStream(const nsACString& aOrigin) ++ : mOrigin(aOrigin) ++ { } ++ ++ // nsFileStreamBase override ++ virtual nsresult ++ DoOpen() MOZ_OVERRIDE; ++ ++ nsCString mOrigin; ++ nsRefPtr<QuotaObject> mQuotaObject; ++}; ++ ++template <class FileStreamBase> ++class FileQuotaStreamWithWrite : public FileQuotaStream<FileStreamBase> ++{ ++public: ++ // nsFileStreamBase override ++ NS_IMETHOD ++ Write(const char* aBuf, uint32_t aCount, uint32_t* _retval) MOZ_OVERRIDE; ++ ++protected: ++ FileQuotaStreamWithWrite(const nsACString& aOrigin) ++ : FileQuotaStream<FileStreamBase>(aOrigin) ++ { } ++}; ++ ++class FileInputStream : public FileQuotaStream<nsFileInputStream> ++{ ++public: ++ NS_DECL_ISUPPORTS_INHERITED ++ ++ static already_AddRefed<FileInputStream> ++ Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1, ++ int32_t aPerm = -1, int32_t aBehaviorFlags = 0); ++ ++private: ++ FileInputStream(const nsACString& aOrigin) ++ : FileQuotaStream<nsFileInputStream>(aOrigin) ++ { } ++ ++ virtual ~FileInputStream() { ++ Close(); ++ } ++}; ++ ++class FileOutputStream : public FileQuotaStreamWithWrite<nsFileOutputStream> ++{ ++public: ++ NS_DECL_ISUPPORTS_INHERITED ++ ++ static already_AddRefed<FileOutputStream> ++ Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1, ++ int32_t aPerm = -1, int32_t aBehaviorFlags = 0); ++ ++private: ++ FileOutputStream(const nsACString& aOrigin) ++ : FileQuotaStreamWithWrite<nsFileOutputStream>(aOrigin) ++ { } ++ ++ virtual ~FileOutputStream() { ++ Close(); ++ } ++}; ++ ++class FileStream : public FileQuotaStreamWithWrite<nsFileStream> ++{ ++public: ++ NS_DECL_ISUPPORTS_INHERITED ++ ++ static already_AddRefed<FileStream> ++ Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1, ++ int32_t aPerm = -1, int32_t aBehaviorFlags = 0); ++ ++private: ++ FileStream(const nsACString& aOrigin) ++ : FileQuotaStreamWithWrite<nsFileStream>(aOrigin) ++ { } ++ ++ virtual ~FileStream() { ++ Close(); ++ } ++}; ++ ++END_QUOTA_NAMESPACE ++ ++#endif /* mozilla_dom_quota_filestreams_h__ */ +diff --git dom/quota/Makefile.in dom/quota/Makefile.in +new file mode 100644 +index 0000000..49be551 +--- /dev/null ++++ mozilla/dom/quota/Makefile.in +@@ -0,0 +1,33 @@ ++# This Source Code Form is subject to the terms of the Mozilla Public ++# License, v. 2.0. If a copy of the MPL was not distributed with this file, ++# You can obtain one at http://mozilla.org/MPL/2.0/. ++ ++DEPTH = ../.. ++topsrcdir = @top_srcdir@ ++srcdir = @srcdir@ ++VPATH = @srcdir@ ++ ++include $(DEPTH)/config/autoconf.mk ++ ++MODULE = dom ++LIBRARY_NAME = domquota_s ++XPIDL_MODULE = dom_quota ++LIBXUL_LIBRARY = 1 ++FORCE_STATIC_LIB = 1 ++ ++include $(topsrcdir)/dom/dom-config.mk ++ ++EXPORTS_NAMESPACES = mozilla/dom/quota ++ ++CPPSRCS = \ ++ FileStreams.cpp \ ++ QuotaManager.cpp \ ++ $(NULL) ++ ++EXPORTS_mozilla/dom/quota = \ ++ FileStreams.h \ ++ QuotaCommon.h \ ++ QuotaManager.h \ ++ $(NULL) ++ ++include $(topsrcdir)/config/rules.mk +diff --git dom/quota/QuotaCommon.h dom/quota/QuotaCommon.h +new file mode 100644 +index 0000000..a415d17 +--- /dev/null ++++ mozilla/dom/quota/QuotaCommon.h +@@ -0,0 +1,23 @@ ++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* vim: set ts=2 et sw=2 tw=80: */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this file, ++ * You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#ifndef mozilla_dom_quota_quotacommon_h__ ++#define mozilla_dom_quota_quotacommon_h__ ++ ++#include "nsAutoPtr.h" ++#include "nsCOMPtr.h" ++#include "nsDebug.h" ++#include "nsStringGlue.h" ++#include "nsTArray.h" ++ ++#define BEGIN_QUOTA_NAMESPACE \ ++ namespace mozilla { namespace dom { namespace quota { ++#define END_QUOTA_NAMESPACE \ ++ } /* namespace quota */ } /* namespace dom */ } /* namespace mozilla */ ++#define USING_QUOTA_NAMESPACE \ ++ using namespace mozilla::dom::quota; ++ ++#endif // mozilla_dom_quota_quotacommon_h__ +diff --git dom/quota/QuotaManager.cpp dom/quota/QuotaManager.cpp +new file mode 100644 +index 0000000..b251606 +--- /dev/null ++++ mozilla/dom/quota/QuotaManager.cpp +@@ -0,0 +1,294 @@ ++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* vim: set ts=2 et sw=2 tw=80: */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this file, ++ * You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#include "QuotaManager.h" ++ ++#include "nsIFile.h" ++ ++#include "mozilla/ClearOnShutdown.h" ++#include "nsComponentManagerUtils.h" ++ ++#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h" ++ ++USING_QUOTA_NAMESPACE ++ ++namespace { ++ ++nsAutoPtr<QuotaManager> gInstance; ++ ++PLDHashOperator ++RemoveQuotaForPatternCallback(const nsACString& aKey, ++ nsRefPtr<OriginInfo>& aValue, ++ void* aUserArg) ++{ ++ NS_ASSERTION(!aKey.IsEmpty(), "Empty key!"); ++ NS_ASSERTION(aValue, "Null pointer!"); ++ NS_ASSERTION(aUserArg, "Null pointer!"); ++ ++ const nsACString* pattern = ++ static_cast<const nsACString*>(aUserArg); ++ ++ if (StringBeginsWith(aKey, *pattern)) { ++ return PL_DHASH_REMOVE; ++ } ++ ++ return PL_DHASH_NEXT; ++} ++ ++} // anonymous namespace ++ ++void ++QuotaObject::AddRef() ++{ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ if (!quotaManager) { ++ NS_ERROR("Null quota manager, this shouldn't happen, possible leak!"); ++ ++ NS_AtomicIncrementRefcnt(mRefCnt); ++ ++ return; ++ } ++ ++ MutexAutoLock lock(quotaManager->mQuotaMutex); ++ ++ ++mRefCnt; ++} ++ ++void ++QuotaObject::Release() ++{ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ if (!quotaManager) { ++ NS_ERROR("Null quota manager, this shouldn't happen, possible leak!"); ++ ++ nsrefcnt count = NS_AtomicDecrementRefcnt(mRefCnt); ++ if (count == 0) { ++ mRefCnt = 1; ++ delete this; ++ } ++ ++ return; ++ } ++ ++ { ++ MutexAutoLock lock(quotaManager->mQuotaMutex); ++ ++ --mRefCnt; ++ ++ if (mRefCnt > 0) { ++ return; ++ } ++ ++ if (mOriginInfo) { ++ mOriginInfo->mQuotaObjects.Remove(mPath); ++ } ++ } ++ ++ delete this; ++} ++ ++void ++QuotaObject::UpdateSize(int64_t aSize) ++{ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ MutexAutoLock lock(quotaManager->mQuotaMutex); ++ ++ if (mOriginInfo) { ++ mOriginInfo->mUsage -= mSize; ++ mSize = aSize; ++ mOriginInfo->mUsage += mSize; ++ } ++} ++ ++bool ++QuotaObject::MaybeAllocateMoreSpace(int64_t aOffset, int32_t aCount) ++{ ++ int64_t end = aOffset + aCount; ++ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ MutexAutoLock lock(quotaManager->mQuotaMutex); ++ ++ if (mSize >= end || !mOriginInfo) { ++ return true; ++ } ++ ++ int64_t newUsage = mOriginInfo->mUsage - mSize + end; ++ if (newUsage > mOriginInfo->mLimit) { ++ if (!indexedDB::IndexedDatabaseManager::QuotaIsLifted()) { ++ return false; ++ } ++ ++ nsCString origin = mOriginInfo->mOrigin; ++ ++ mOriginInfo->LockedClearOriginInfos(); ++ NS_ASSERTION(!mOriginInfo, ++ "Should have cleared in LockedClearOriginInfos!"); ++ ++ quotaManager->mOriginInfos.Remove(origin); ++ ++ mSize = end; ++ ++ return true; ++ } ++ ++ mOriginInfo->mUsage = newUsage; ++ mSize = end; ++ ++ return true; ++} ++ ++#ifdef DEBUG ++void ++OriginInfo::LockedClearOriginInfos() ++{ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ quotaManager->mQuotaMutex.AssertCurrentThreadOwns(); ++ ++ mQuotaObjects.EnumerateRead(ClearOriginInfoCallback, nullptr); ++} ++#endif ++ ++// static ++PLDHashOperator ++OriginInfo::ClearOriginInfoCallback(const nsAString& aKey, ++ QuotaObject* aValue, ++ void* aUserArg) ++{ ++ NS_ASSERTION(!aKey.IsEmpty(), "Empty key!"); ++ NS_ASSERTION(aValue, "Null pointer!"); ++ ++ aValue->mOriginInfo = nullptr; ++ ++ return PL_DHASH_NEXT; ++} ++ ++// static ++QuotaManager* ++QuotaManager::GetOrCreate() ++{ ++ if (!gInstance) { ++ NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); ++ ++ gInstance = new QuotaManager(); ++ ++ ClearOnShutdown(&gInstance); ++ } ++ ++ return gInstance; ++} ++ ++// static ++QuotaManager* ++QuotaManager::Get() ++{ ++ // Does not return an owning reference. ++ return gInstance; ++} ++ ++void ++QuotaManager::InitQuotaForOrigin(const nsACString& aOrigin, ++ int64_t aLimit, ++ int64_t aUsage) ++{ ++ OriginInfo* info = new OriginInfo(aOrigin, aLimit * 1024 * 1024, aUsage); ++ ++ MutexAutoLock lock(mQuotaMutex); ++ ++ NS_ASSERTION(!mOriginInfos.GetWeak(aOrigin), "Replacing an existing entry!"); ++ mOriginInfos.Put(aOrigin, info); ++} ++ ++void ++QuotaManager::DecreaseUsageForOrigin(const nsACString& aOrigin, ++ int64_t aSize) ++{ ++ MutexAutoLock lock(mQuotaMutex); ++ ++ nsRefPtr<OriginInfo> originInfo; ++ mOriginInfos.Get(aOrigin, getter_AddRefs(originInfo)); ++ ++ if (originInfo) { ++ originInfo->mUsage -= aSize; ++ } ++} ++ ++void ++QuotaManager::RemoveQuotaForPattern(const nsACString& aPattern) ++{ ++ NS_ASSERTION(!aPattern.IsEmpty(), "Empty pattern!"); ++ ++ MutexAutoLock lock(mQuotaMutex); ++ ++ mOriginInfos.Enumerate(RemoveQuotaForPatternCallback, ++ const_cast<nsACString*>(&aPattern)); ++} ++ ++already_AddRefed<QuotaObject> ++QuotaManager::GetQuotaObject(const nsACString& aOrigin, ++ nsIFile* aFile) ++{ ++ NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); ++ ++ nsString path; ++ nsresult rv = aFile->GetPath(path); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ ++ int64_t fileSize; ++ ++ bool exists; ++ rv = aFile->Exists(&exists); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ ++ if (exists) { ++ rv = aFile->GetFileSize(&fileSize); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ } ++ else { ++ fileSize = 0; ++ } ++ ++ QuotaObject* info = nullptr; ++ { ++ MutexAutoLock lock(mQuotaMutex); ++ ++ nsRefPtr<OriginInfo> originInfo; ++ mOriginInfos.Get(aOrigin, getter_AddRefs(originInfo)); ++ ++ if (!originInfo) { ++ return nullptr; ++ } ++ ++ originInfo->mQuotaObjects.Get(path, &info); ++ ++ if (!info) { ++ info = new QuotaObject(originInfo, path, fileSize); ++ originInfo->mQuotaObjects.Put(path, info); ++ } ++ } ++ ++ nsRefPtr<QuotaObject> result = info; ++ return result.forget(); ++} ++ ++already_AddRefed<QuotaObject> ++QuotaManager::GetQuotaObject(const nsACString& aOrigin, ++ const nsAString& aPath) ++{ ++ nsresult rv; ++ nsCOMPtr<nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ ++ rv = file->InitWithPath(aPath); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ ++ return GetQuotaObject(aOrigin, file); ++} +diff --git dom/quota/QuotaManager.h dom/quota/QuotaManager.h +new file mode 100644 +index 0000000..e19acdd +--- /dev/null ++++ mozilla/dom/quota/QuotaManager.h +@@ -0,0 +1,147 @@ ++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* vim: set ts=2 et sw=2 tw=80: */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this file, ++ * You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#ifndef mozilla_dom_quota_quotamanager_h__ ++#define mozilla_dom_quota_quotamanager_h__ ++ ++#include "QuotaCommon.h" ++ ++#include "mozilla/Mutex.h" ++#include "nsDataHashtable.h" ++#include "nsRefPtrHashtable.h" ++#include "nsThreadUtils.h" ++ ++BEGIN_QUOTA_NAMESPACE ++ ++class OriginInfo; ++class QuotaManager; ++ ++class QuotaObject ++{ ++ friend class OriginInfo; ++ friend class QuotaManager; ++ ++public: ++ void ++ AddRef(); ++ ++ void ++ Release(); ++ ++ void ++ UpdateSize(int64_t aSize); ++ ++ bool ++ MaybeAllocateMoreSpace(int64_t aOffset, int32_t aCount); ++ ++private: ++ QuotaObject(OriginInfo* aOriginInfo, const nsAString& aPath, int64_t aSize) ++ : mOriginInfo(aOriginInfo), mPath(aPath), mSize(aSize) ++ { } ++ ++ virtual ~QuotaObject() ++ { } ++ ++ nsAutoRefCnt mRefCnt; ++ ++ OriginInfo* mOriginInfo; ++ nsString mPath; ++ int64_t mSize; ++}; ++ ++class OriginInfo ++{ ++ friend class QuotaManager; ++ friend class QuotaObject; ++ ++public: ++ OriginInfo(const nsACString& aOrigin, int64_t aLimit, int64_t aUsage) ++ : mOrigin(aOrigin), mLimit(aLimit), mUsage(aUsage) ++ { ++ mQuotaObjects.Init(); ++ } ++ ++ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OriginInfo) ++ ++private: ++ void ++#ifdef DEBUG ++ LockedClearOriginInfos(); ++#else ++ LockedClearOriginInfos() ++ { ++ mQuotaObjects.EnumerateRead(ClearOriginInfoCallback, nullptr); ++ } ++#endif ++ ++ static PLDHashOperator ++ ClearOriginInfoCallback(const nsAString& aKey, ++ QuotaObject* aValue, void* aUserArg); ++ ++ nsDataHashtable<nsStringHashKey, QuotaObject*> mQuotaObjects; ++ ++ nsCString mOrigin; ++ int64_t mLimit; ++ int64_t mUsage; ++}; ++ ++class QuotaManager ++{ ++ friend class nsAutoPtr<QuotaManager>; ++ friend class OriginInfo; ++ friend class QuotaObject; ++ ++public: ++ // Returns a non-owning reference. ++ static QuotaManager* ++ GetOrCreate(); ++ ++ // Returns a non-owning reference. ++ static QuotaManager* ++ Get(); ++ ++ void ++ InitQuotaForOrigin(const nsACString& aOrigin, ++ int64_t aLimit, ++ int64_t aUsage); ++ ++ void ++ DecreaseUsageForOrigin(const nsACString& aOrigin, ++ int64_t aSize); ++ ++ void ++ RemoveQuotaForPattern(const nsACString& aPattern); ++ ++ already_AddRefed<QuotaObject> ++ GetQuotaObject(const nsACString& aOrigin, ++ nsIFile* aFile); ++ ++ already_AddRefed<QuotaObject> ++ GetQuotaObject(const nsACString& aOrigin, ++ const nsAString& aPath); ++ ++private: ++ QuotaManager() ++ : mQuotaMutex("QuotaManager.mQuotaMutex") ++ { ++ NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); ++ ++ mOriginInfos.Init(); ++ } ++ ++ virtual ~QuotaManager() ++ { ++ NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); ++ } ++ ++ mozilla::Mutex mQuotaMutex; ++ ++ nsRefPtrHashtable<nsCStringHashKey, OriginInfo> mOriginInfos; ++}; ++ ++END_QUOTA_NAMESPACE ++ ++#endif /* mozilla_dom_quota_quotamanager_h__ */ +diff --git layout/build/Makefile.in layout/build/Makefile.in +index e6b32da..496b55f 100644 +--- mozilla/layout/build/Makefile.in ++++ mozilla/layout/build/Makefile.in +@@ -69,6 +69,7 @@ SHARED_LIBRARY_LIBS = \ + $(DEPTH)/dom/encoding/$(LIB_PREFIX)domencoding_s.$(LIB_SUFFIX) \ + $(DEPTH)/dom/file/$(LIB_PREFIX)domfile_s.$(LIB_SUFFIX) \ + $(DEPTH)/dom/power/$(LIB_PREFIX)dom_power_s.$(LIB_SUFFIX) \ ++ $(DEPTH)/dom/quota/$(LIB_PREFIX)domquota_s.$(LIB_SUFFIX) \ + $(DEPTH)/dom/settings/$(LIB_PREFIX)jsdomsettings_s.$(LIB_SUFFIX) \ + $(DEPTH)/dom/permission/$(LIB_PREFIX)jsdompermissionsettings_s.$(LIB_SUFFIX) \ + $(DEPTH)/dom/network/src/$(LIB_PREFIX)dom_network_s.$(LIB_SUFFIX) \ +diff --git netwerk/base/src/Makefile.in netwerk/base/src/Makefile.in +index 0c0d60e..e8cef48 100644 +--- mozilla/netwerk/base/src/Makefile.in ++++ mozilla/netwerk/base/src/Makefile.in +@@ -19,6 +19,7 @@ LIBXUL_LIBRARY = 1 + EXPORTS = \ + nsMIMEInputStream.h \ + nsURLHelper.h \ ++ nsFileStreams.h \ + $(NULL) + + EXPORTS_NAMESPACES = mozilla/net +diff --git netwerk/base/src/nsFileStreams.cpp netwerk/base/src/nsFileStreams.cpp +index 2420ffc..ecc26aa 100644 +--- mozilla/netwerk/base/src/nsFileStreams.cpp ++++ mozilla/netwerk/base/src/nsFileStreams.cpp +@@ -51,7 +51,9 @@ nsFileStreamBase::~nsFileStreamBase() + Close(); + } + +-NS_IMPL_THREADSAFE_ISUPPORTS1(nsFileStreamBase, nsISeekableStream) ++NS_IMPL_THREADSAFE_ISUPPORTS2(nsFileStreamBase, ++ nsISeekableStream, ++ nsIFileMetadata) + + NS_IMETHODIMP + nsFileStreamBase::Seek(int32_t whence, int64_t offset) +@@ -124,6 +126,52 @@ nsFileStreamBase::SetEOF() + return NS_OK; + } + ++NS_IMETHODIMP ++nsFileStreamBase::GetSize(int64_t* _retval) ++{ ++ nsresult rv = DoPendingOpen(); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ if (!mFD) { ++ return NS_BASE_STREAM_CLOSED; ++ } ++ ++ PRFileInfo64 info; ++ if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) { ++ return NS_BASE_STREAM_OSERROR; ++ } ++ ++ *_retval = int64_t(info.size); ++ ++ return NS_OK; ++} ++ ++NS_IMETHODIMP ++nsFileStreamBase::GetLastModified(int64_t* _retval) ++{ ++ nsresult rv = DoPendingOpen(); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ if (!mFD) { ++ return NS_BASE_STREAM_CLOSED; ++ } ++ ++ PRFileInfo64 info; ++ if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) { ++ return NS_BASE_STREAM_OSERROR; ++ } ++ ++ int64_t modTime = int64_t(info.modifyTime); ++ if (modTime == 0) { ++ *_retval = 0; ++ } ++ else { ++ *_retval = modTime / int64_t(PR_USEC_PER_MSEC); ++ } ++ ++ return NS_OK; ++} ++ + nsresult + nsFileStreamBase::Close() + { +@@ -934,13 +982,12 @@ nsSafeFileOutputStream::Write(const char *buf, uint32_t count, uint32_t *result) + //////////////////////////////////////////////////////////////////////////////// + // nsFileStream + +-NS_IMPL_ISUPPORTS_INHERITED4(nsFileStream, ++NS_IMPL_ISUPPORTS_INHERITED3(nsFileStream, + nsFileStreamBase, + nsIInputStream, + nsIOutputStream, +- nsIFileStream, +- nsIFileMetadata) +- ++ nsIFileStream) ++ + NS_IMETHODIMP + nsFileStream::Init(nsIFile* file, int32_t ioFlags, int32_t perm, + int32_t behaviorFlags) +@@ -959,50 +1006,4 @@ nsFileStream::Init(nsIFile* file, int32_t ioFlags, int32_t perm, + mBehaviorFlags & nsIFileStream::DEFER_OPEN); + } + +-NS_IMETHODIMP +-nsFileStream::GetSize(int64_t* _retval) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mFD) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- PRFileInfo64 info; +- if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) { +- return NS_BASE_STREAM_OSERROR; +- } +- +- *_retval = int64_t(info.size); +- +- return NS_OK; +-} +- +-NS_IMETHODIMP +-nsFileStream::GetLastModified(int64_t* _retval) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mFD) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- PRFileInfo64 info; +- if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) { +- return NS_BASE_STREAM_OSERROR; +- } +- +- int64_t modTime = int64_t(info.modifyTime); +- if (modTime == 0) { +- *_retval = 0; +- } +- else { +- *_retval = modTime / int64_t(PR_USEC_PER_MSEC); +- } +- +- return NS_OK; +-} +- + //////////////////////////////////////////////////////////////////////////////// +diff --git netwerk/base/src/nsFileStreams.h netwerk/base/src/nsFileStreams.h +index 13e5b45..1aa6a82 100644 +--- mozilla/netwerk/base/src/nsFileStreams.h ++++ mozilla/netwerk/base/src/nsFileStreams.h +@@ -24,11 +24,13 @@ + + //////////////////////////////////////////////////////////////////////////////// + +-class nsFileStreamBase : public nsISeekableStream ++class nsFileStreamBase : public nsISeekableStream, ++ public nsIFileMetadata + { + public: + NS_DECL_ISUPPORTS + NS_DECL_NSISEEKABLESTREAM ++ NS_DECL_NSIFILEMETADATA + + nsFileStreamBase(); + virtual ~nsFileStreamBase(); +@@ -124,8 +126,8 @@ public: + NS_IMETHOD IsNonBlocking(bool* _retval) + { + return nsFileStreamBase::IsNonBlocking(_retval); +- } +- ++ } ++ + // Overrided from nsFileStreamBase + NS_IMETHOD Seek(int32_t aWhence, int64_t aOffset); + +@@ -260,13 +262,11 @@ protected: + class nsFileStream : public nsFileStreamBase, + public nsIInputStream, + public nsIOutputStream, +- public nsIFileStream, +- public nsIFileMetadata ++ public nsIFileStream + { + public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIFILESTREAM +- NS_DECL_NSIFILEMETADATA + NS_FORWARD_NSIINPUTSTREAM(nsFileStreamBase::) + + // Can't use NS_FORWARD_NSIOUTPUTSTREAM due to overlapping methods +diff --git storage/public/Makefile.in storage/public/Makefile.in +index c485d4e..c05e6f3 100644 +--- mozilla/storage/public/Makefile.in ++++ mozilla/storage/public/Makefile.in +@@ -36,7 +36,6 @@ XPIDLSRCS = \ + mozIStorageCompletionCallback.idl \ + mozIStorageBaseStatement.idl \ + mozIStorageAsyncStatement.idl \ +- mozIStorageServiceQuotaManagement.idl \ + mozIStorageVacuumParticipant.idl \ + $(NULL) + # SEE ABOVE NOTE! +diff --git storage/public/mozIStorageService.idl storage/public/mozIStorageService.idl +index 3087a11..483649b 100644 +--- mozilla/storage/public/mozIStorageService.idl ++++ mozilla/storage/public/mozIStorageService.idl +@@ -7,6 +7,7 @@ + + interface mozIStorageConnection; + interface nsIFile; ++interface nsIFileURL; + + /** + * The mozIStorageService interface is intended to be implemented by +@@ -15,7 +16,7 @@ interface nsIFile; + * + * This is the only way to open a database connection. + */ +-[scriptable, uuid(fe8e95cb-b377-4c8d-bccb-d9198c67542b)] ++[scriptable, uuid(12bfad34-cca3-40fb-8736-d8bf9db61a27)] + interface mozIStorageService : nsISupports { + /** + * Get a connection to a named special database storage. +@@ -106,6 +107,16 @@ interface mozIStorageService : nsISupports { + */ + mozIStorageConnection openUnsharedDatabase(in nsIFile aDatabaseFile); + ++ /** ++ * See openDatabase(). Exactly the same only initialized with a file URL. ++ * Custom parameters can be passed to SQLite and VFS implementations through ++ * the query part of the URL. ++ * ++ * @param aURL ++ * A nsIFileURL that represents the database that is to be opened. ++ */ ++ mozIStorageConnection openDatabaseWithFileURL(in nsIFileURL aFileURL); ++ + /* + * Utilities + */ +diff --git storage/public/mozIStorageServiceQuotaManagement.idl storage/public/mozIStorageServiceQuotaManagement.idl +deleted file mode 100644 +index ee5086b..0000000 +--- mozilla/storage/public/mozIStorageServiceQuotaManagement.idl ++++ /dev/null +@@ -1,99 +0,0 @@ +-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +-/* vim: set ts=2 et sw=2 tw=80: */ +-/* This Source Code Form is subject to the terms of the Mozilla Public +- * License, v. 2.0. If a copy of the MPL was not distributed with this +- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +- +-#include "nsISupports.idl" +- +-interface mozIStorageConnection; +-interface nsIFile; +- +-[scriptable, function, uuid(ae94f0a5-ebdf-48f4-9959-085e13235d8d)] +-interface mozIStorageQuotaCallback : nsISupports +-{ +- /** +- * Called when the file size quota for a group of databases is exceeded. +- * +- * @param aFilename +- * The filename of the database that has exceeded the quota. +- * +- * @param aCurrentSizeLimit +- * The current size (in bytes) of the quota. +- * +- * @param aCurrentTotalSize +- * The current size of all databases in the quota group. +- * +- * @param aUserData +- * Any additional data that was provided to the +- * setQuotaForFilenamePattern function. +- * +- * @returns A new quota size. A new quota of 0 will disable the quota callback +- * and any quota value less than aCurrentTotalSize will cause the +- * database operation to fail with NS_ERROR_FILE_NO_DEVICE_SPACE. +- */ +- long long quotaExceeded(in ACString aFilename, +- in long long aCurrentSizeLimit, +- in long long aCurrentTotalSize, +- in nsISupports aUserData); +-}; +- +-/** +- * This is a temporary interface that should eventually merge with +- * mozIStorageService. +- */ +-[scriptable, uuid(4d81faf5-fe01-428b-99b8-c94cba12fd72)] +-interface mozIStorageServiceQuotaManagement : nsISupports +-{ +- /** +- * See mozIStorageService.openDatabase. Exactly the same only with a custom +- * SQLite VFS. +- */ +- mozIStorageConnection openDatabaseWithVFS(in nsIFile aDatabaseFile, +- in ACString aVFSName); +- +- /** +- * Set a file size quota for a group of databases matching the given filename +- * pattern, optionally specifying a callback when the quota is exceeded. +- * +- * @param aPattern +- * A pattern to match filenames for inclusion in the quota system. May +- * contain the following special characters: +- * '*' Matches any sequence of zero or more characters. +- * '?' Matches exactly one character. +- * [...] Matches one character from the enclosed list of characters. +- * [^...] Matches one character not in the enclosed list. +- * +- * @param aSizeLimit +- * The size limit (in bytes) for the quota group. +- * +- * @param aCallback +- * A callback that will be used when the quota is exceeded. +- * +- * @param aUserData +- * Additional information to be passed to the callback. +- */ +- void setQuotaForFilenamePattern(in ACString aPattern, +- in long long aSizeLimit, +- in mozIStorageQuotaCallback aCallback, +- in nsISupports aUserData); +- +- /** +- * Adds, removes, or updates the file size information maintained by the quota +- * system for files not opened through openDatabaseWithVFS(). +- * +- * Use this function when you want files to be included in quota calculations +- * that are either a) not SQLite databases, or b) SQLite databases that have +- * not been opened. +- * +- * This function will have no effect on files that do not match an existing +- * quota pattern (set previously by setQuotaForFilenamePattern()). +- * +- * @param aFile +- * The file for which quota information should be updated. If the file +- * exists then its size information will be added or refreshed. If the +- * file does not exist then the file will be removed from tracking +- * under the quota system. +- */ +- void updateQuotaInformationForFile(in nsIFile aFile); +-}; +diff --git storage/public/storage.h storage/public/storage.h +index 8e571e2..08f39f3 100644 +--- mozilla/storage/public/storage.h ++++ mozilla/storage/public/storage.h +@@ -24,7 +24,6 @@ + #include "mozIStorageStatementCallback.h" + #include "mozIStorageBindingParamsArray.h" + #include "mozIStorageBindingParams.h" +-#include "mozIStorageServiceQuotaManagement.h" + #include "mozIStorageVacuumParticipant.h" + #include "mozIStorageCompletionCallback.h" + #include "mozIStorageAsyncStatement.h" +diff --git storage/src/TelemetryVFS.cpp storage/src/TelemetryVFS.cpp +index 60de5c4..e4fce09 100644 +--- mozilla/storage/src/TelemetryVFS.cpp ++++ mozilla/storage/src/TelemetryVFS.cpp +@@ -10,6 +10,7 @@ + #include "sqlite3.h" + #include "nsThreadUtils.h" + #include "mozilla/Util.h" ++#include "mozilla/dom/quota/QuotaManager.h" + + /** + * This preference is a workaround to allow users/sysadmins to identify +@@ -24,6 +25,7 @@ + namespace { + + using namespace mozilla; ++using namespace mozilla::dom::quota; + + struct Histograms { + const char *name; +@@ -82,9 +84,17 @@ private: + }; + + struct telemetry_file { +- sqlite3_file base; // Base class. Must be first +- Histograms *histograms; // histograms pertaining to this file +- sqlite3_file pReal[1]; // This contains the vfs that actually does work ++ // Base class. Must be first ++ sqlite3_file base; ++ ++ // histograms pertaining to this file ++ Histograms *histograms; ++ ++ // quota object for this file ++ nsRefPtr<QuotaObject> quotaObject; ++ ++ // This contains the vfs that actually does work ++ sqlite3_file pReal[1]; + }; + + /* +@@ -99,6 +109,7 @@ xClose(sqlite3_file *pFile) + if( rc==SQLITE_OK ){ + delete p->base.pMethods; + p->base.pMethods = NULL; ++ p->quotaObject = nullptr; + } + return rc; + } +@@ -126,6 +137,9 @@ int + xWrite(sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite_int64 iOfst) + { + telemetry_file *p = (telemetry_file *)pFile; ++ if (p->quotaObject && !p->quotaObject->MaybeAllocateMoreSpace(iOfst, iAmt)) { ++ return SQLITE_FULL; ++ } + IOThreadAutoTimer ioTimer(p->histograms->writeMS); + int rc; + rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst); +@@ -144,6 +158,9 @@ xTruncate(sqlite3_file *pFile, sqlite_int64 size) + int rc; + Telemetry::AutoTimer<Telemetry::MOZ_SQLITE_TRUNCATE_MS> timer; + rc = p->pReal->pMethods->xTruncate(p->pReal, size); ++ if (rc == SQLITE_OK && p->quotaObject) { ++ p->quotaObject->UpdateSize(size); ++ } + return rc; + } + +@@ -300,6 +317,18 @@ xOpen(sqlite3_vfs* vfs, const char *zName, sqlite3_file* pFile, + break; + } + p->histograms = h; ++ ++ const char* origin; ++ if ((flags & SQLITE_OPEN_URI) && ++ (origin = sqlite3_uri_parameter(zName, "origin"))) { ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ MOZ_ASSERT(quotaManager); ++ ++ p->quotaObject = quotaManager->GetQuotaObject(nsDependentCString(origin), ++ NS_ConvertUTF8toUTF16(zName)); ++ ++ } ++ + rc = orig_vfs->xOpen(orig_vfs, zName, p->pReal, flags, pOutFlags); + if( rc != SQLITE_OK ) + return rc; +diff --git storage/src/mozStorageConnection.cpp storage/src/mozStorageConnection.cpp +index 3afd3e1b..430824a 100644 +--- mozilla/storage/src/mozStorageConnection.cpp ++++ mozilla/storage/src/mozStorageConnection.cpp +@@ -12,6 +12,7 @@ + #include "nsIMemoryReporter.h" + #include "nsThreadUtils.h" + #include "nsIFile.h" ++#include "nsIFileURL.h" + #include "mozilla/Telemetry.h" + #include "mozilla/Mutex.h" + #include "mozilla/CondVar.h" +@@ -471,34 +472,83 @@ Connection::getAsyncExecutionTarget() + } + + nsresult +-Connection::initialize(nsIFile *aDatabaseFile, +- const char* aVFSName) ++Connection::initialize() + { + NS_ASSERTION (!mDBConn, "Initialize called on already opened database!"); + SAMPLE_LABEL("storage", "Connection::initialize"); + +- int srv; +- nsresult rv; ++ // in memory database requested, sqlite uses a magic file name ++ int srv = ::sqlite3_open_v2(":memory:", &mDBConn, mFlags, NULL); ++ if (srv != SQLITE_OK) { ++ mDBConn = nullptr; ++ return convertResultCode(srv); ++ } ++ ++ return initializeInternal(nullptr); ++} ++ ++nsresult ++Connection::initialize(nsIFile *aDatabaseFile) ++{ ++ NS_ASSERTION (aDatabaseFile, "Passed null file!"); ++ NS_ASSERTION (!mDBConn, "Initialize called on already opened database!"); ++ SAMPLE_LABEL("storage", "Connection::initialize"); + + mDatabaseFile = aDatabaseFile; + +- if (aDatabaseFile) { +- nsAutoString path; +- rv = aDatabaseFile->GetPath(path); +- NS_ENSURE_SUCCESS(rv, rv); ++ nsAutoString path; ++ nsresult rv = aDatabaseFile->GetPath(path); ++ NS_ENSURE_SUCCESS(rv, rv); + +- srv = ::sqlite3_open_v2(NS_ConvertUTF16toUTF8(path).get(), &mDBConn, mFlags, +- aVFSName); +- } +- else { +- // in memory database requested, sqlite uses a magic file name +- srv = ::sqlite3_open_v2(":memory:", &mDBConn, mFlags, aVFSName); ++ int srv = ::sqlite3_open_v2(NS_ConvertUTF16toUTF8(path).get(), &mDBConn, ++ mFlags, NULL); ++ if (srv != SQLITE_OK) { ++ mDBConn = nullptr; ++ return convertResultCode(srv); + } ++ ++ rv = initializeInternal(aDatabaseFile); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ mDatabaseFile = aDatabaseFile; ++ ++ return NS_OK; ++} ++ ++nsresult ++Connection::initialize(nsIFileURL *aFileURL) ++{ ++ NS_ASSERTION (aFileURL, "Passed null file URL!"); ++ NS_ASSERTION (!mDBConn, "Initialize called on already opened database!"); ++ SAMPLE_LABEL("storage", "Connection::initialize"); ++ ++ nsCOMPtr<nsIFile> databaseFile; ++ nsresult rv = aFileURL->GetFile(getter_AddRefs(databaseFile)); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ nsAutoCString spec; ++ rv = aFileURL->GetSpec(spec); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ int srv = ::sqlite3_open_v2(spec.get(), &mDBConn, mFlags, NULL); + if (srv != SQLITE_OK) { + mDBConn = nullptr; + return convertResultCode(srv); + } + ++ rv = initializeInternal(databaseFile); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ mFileURL = aFileURL; ++ mDatabaseFile = databaseFile; ++ ++ return NS_OK; ++} ++ ++ ++nsresult ++Connection::initializeInternal(nsIFile* aDatabaseFile) ++{ + // Properly wrap the database handle's mutex. + sharedDBMutex.initWithMutex(sqlite3_db_mutex(mDBConn)); + +@@ -522,14 +572,14 @@ Connection::initialize(nsIFile *aDatabaseFile, + nsAutoCString pageSizeQuery(MOZ_STORAGE_UNIQUIFY_QUERY_STR + "PRAGMA page_size = "); + pageSizeQuery.AppendInt(pageSize); +- rv = ExecuteSimpleSQL(pageSizeQuery); ++ nsresult rv = ExecuteSimpleSQL(pageSizeQuery); + NS_ENSURE_SUCCESS(rv, rv); + + // Get the current page_size, since it may differ from the specified value. + sqlite3_stmt *stmt; + NS_NAMED_LITERAL_CSTRING(pragma_page_size, + MOZ_STORAGE_UNIQUIFY_QUERY_STR "PRAGMA page_size"); +- srv = prepareStatement(pragma_page_size, &stmt); ++ int srv = prepareStatement(pragma_page_size, &stmt); + if (srv == SQLITE_OK) { + if (SQLITE_ROW == stepStatement(stmt)) { + pageSize = ::sqlite3_column_int64(stmt, 0); +@@ -962,7 +1012,8 @@ Connection::Clone(bool aReadOnly, + nsRefPtr<Connection> clone = new Connection(mStorageService, flags); + NS_ENSURE_TRUE(clone, NS_ERROR_OUT_OF_MEMORY); + +- nsresult rv = clone->initialize(mDatabaseFile); ++ nsresult rv = mFileURL ? clone->initialize(mFileURL) ++ : clone->initialize(mDatabaseFile); + NS_ENSURE_SUCCESS(rv, rv); + + // Copy over pragmas from the original connection. +diff --git storage/src/mozStorageConnection.h storage/src/mozStorageConnection.h +index b71f5db..97f5cf8 100644 +--- mozilla/storage/src/mozStorageConnection.h ++++ mozilla/storage/src/mozStorageConnection.h +@@ -25,6 +25,7 @@ + + struct PRLock; + class nsIFile; ++class nsIFileURL; + class nsIEventTarget; + class nsIThread; + +@@ -63,18 +64,27 @@ public: + Connection(Service *aService, int aFlags); + + /** ++ * Creates the connection to an in-memory database. ++ */ ++ nsresult initialize(); ++ ++ /** + * Creates the connection to the database. + * + * @param aDatabaseFile + * The nsIFile of the location of the database to open, or create if it +- * does not exist. Passing in nullptr here creates an in-memory +- * database. +- * @param aVFSName +- * The VFS that SQLite will use when opening this database. NULL means +- * "default". ++ * does not exist. + */ +- nsresult initialize(nsIFile *aDatabaseFile, +- const char* aVFSName = NULL); ++ nsresult initialize(nsIFile *aDatabaseFile); ++ ++ /** ++ * Creates the connection to the database. ++ * ++ * @param aFileURL ++ * The nsIFileURL of the location of the database to open, or create if it ++ * does not exist. ++ */ ++ nsresult initialize(nsIFileURL *aFileURL); + + // fetch the native handle + sqlite3 *GetNativeConnection() { return mDBConn; } +@@ -155,6 +165,8 @@ public: + private: + ~Connection(); + ++ nsresult initializeInternal(nsIFile *aDatabaseFile); ++ + /** + * Sets the database into a closed state so no further actions can be + * performed. +@@ -206,6 +218,7 @@ private: + int progressHandler(); + + sqlite3 *mDBConn; ++ nsCOMPtr<nsIFileURL> mFileURL; + nsCOMPtr<nsIFile> mDatabaseFile; + + /** +diff --git storage/src/mozStorageService.cpp storage/src/mozStorageService.cpp +index 00661d6..862a7da 100644 +--- mozilla/storage/src/mozStorageService.cpp ++++ mozilla/storage/src/mozStorageService.cpp +@@ -24,8 +24,6 @@ + #include "mozilla/Preferences.h" + + #include "sqlite3.h" +-#include "test_quota.h" +-#include "test_quota.c" + + #ifdef SQLITE_OS_WIN + // "windows.h" was included and it can #define lots of things we care about... +@@ -35,61 +33,6 @@ + #include "nsIPromptService.h" + #include "nsIMemoryReporter.h" + +-namespace { +- +-class QuotaCallbackData +-{ +-public: +- QuotaCallbackData(mozIStorageQuotaCallback *aCallback, +- nsISupports *aUserData) +- : callback(aCallback), userData(aUserData) +- { +- MOZ_COUNT_CTOR(QuotaCallbackData); +- } +- +- ~QuotaCallbackData() +- { +- MOZ_COUNT_DTOR(QuotaCallbackData); +- } +- +- static void Callback(const char *zFilename, +- sqlite3_int64 *piLimit, +- sqlite3_int64 iSize, +- void *pArg) +- { +- NS_ASSERTION(zFilename && strlen(zFilename), "Null or empty filename!"); +- NS_ASSERTION(piLimit, "Null pointer!"); +- +- QuotaCallbackData *data = static_cast<QuotaCallbackData*>(pArg); +- if (!data) { +- // No callback specified, return immediately. +- return; +- } +- +- NS_ASSERTION(data->callback, "Should never have a null callback!"); +- +- nsDependentCString filename(zFilename); +- +- int64_t newLimit; +- if (NS_SUCCEEDED(data->callback->QuotaExceeded(filename, *piLimit, +- iSize, data->userData, +- &newLimit))) { +- *piLimit = newLimit; +- } +- } +- +- static void Destroy(void *aUserData) +- { +- delete static_cast<QuotaCallbackData*>(aUserData); +- } +- +-private: +- nsCOMPtr<mozIStorageQuotaCallback> callback; +- nsCOMPtr<nsISupports> userData; +-}; +- +-} // anonymous namespace +- + //////////////////////////////////////////////////////////////////////////////// + //// Defines + +@@ -345,11 +288,10 @@ private: + //////////////////////////////////////////////////////////////////////////////// + //// Service + +-NS_IMPL_THREADSAFE_ISUPPORTS3( ++NS_IMPL_THREADSAFE_ISUPPORTS2( + Service, + mozIStorageService, +- nsIObserver, +- mozIStorageServiceQuotaManagement ++ nsIObserver + ) + + Service *Service::gService = nullptr; +@@ -438,10 +380,6 @@ Service::~Service() + + // Shutdown the sqlite3 API. Warn if shutdown did not turn out okay, but + // there is nothing actionable we can do in that case. +- rc = ::sqlite3_quota_shutdown(); +- if (rc != SQLITE_OK) +- NS_WARNING("sqlite3 did not shutdown cleanly."); +- + rc = ::sqlite3_shutdown(); + if (rc != SQLITE_OK) + NS_WARNING("sqlite3 did not shutdown cleanly."); +@@ -636,9 +574,6 @@ Service::initialize() + } else { + NS_WARNING("Failed to register telemetry VFS"); + } +- rc = ::sqlite3_quota_initialize("telemetry-vfs", 0); +- if (rc != SQLITE_OK) +- return convertResultCode(rc); + + // Set the default value for the toolkit.storage.synchronous pref. It will be + // updated with the user preference on the main thread. +@@ -739,28 +674,24 @@ Service::OpenSpecialDatabase(const char *aStorageKey, + // connection to use a memory DB. + } + else if (::strcmp(aStorageKey, "profile") == 0) { +- + rv = NS_GetSpecialDirectory(NS_APP_STORAGE_50_FILE, + getter_AddRefs(storageFile)); + NS_ENSURE_SUCCESS(rv, rv); + +- nsString filename; +- storageFile->GetPath(filename); +- nsCString filename8 = NS_ConvertUTF16toUTF8(filename.get()); + // fall through to DB initialization + } + else { + return NS_ERROR_INVALID_ARG; + } + +- Connection *msc = new Connection(this, SQLITE_OPEN_READWRITE); +- NS_ENSURE_TRUE(msc, NS_ERROR_OUT_OF_MEMORY); ++ nsRefPtr<Connection> msc = new Connection(this, SQLITE_OPEN_READWRITE); + +- rv = msc->initialize(storageFile); ++ rv = storageFile ? msc->initialize(storageFile) : msc->initialize(); + NS_ENSURE_SUCCESS(rv, rv); + +- NS_ADDREF(*_connection = msc); ++ msc.forget(_connection); + return NS_OK; ++ + } + + NS_IMETHODIMP +@@ -774,12 +705,11 @@ Service::OpenDatabase(nsIFile *aDatabaseFile, + int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE | + SQLITE_OPEN_CREATE; + nsRefPtr<Connection> msc = new Connection(this, flags); +- NS_ENSURE_TRUE(msc, NS_ERROR_OUT_OF_MEMORY); + + nsresult rv = msc->initialize(aDatabaseFile); + NS_ENSURE_SUCCESS(rv, rv); + +- NS_ADDREF(*_connection = msc); ++ msc.forget(_connection); + return NS_OK; + } + +@@ -794,12 +724,30 @@ Service::OpenUnsharedDatabase(nsIFile *aDatabaseFile, + int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_PRIVATECACHE | + SQLITE_OPEN_CREATE; + nsRefPtr<Connection> msc = new Connection(this, flags); +- NS_ENSURE_TRUE(msc, NS_ERROR_OUT_OF_MEMORY); + + nsresult rv = msc->initialize(aDatabaseFile); + NS_ENSURE_SUCCESS(rv, rv); + +- NS_ADDREF(*_connection = msc); ++ msc.forget(_connection); ++ return NS_OK; ++} ++ ++NS_IMETHODIMP ++Service::OpenDatabaseWithFileURL(nsIFileURL *aFileURL, ++ mozIStorageConnection **_connection) ++{ ++ NS_ENSURE_ARG(aFileURL); ++ ++ // Always ensure that SQLITE_OPEN_CREATE is passed in for compatibility ++ // reasons. ++ int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE | ++ SQLITE_OPEN_CREATE | SQLITE_OPEN_URI; ++ nsRefPtr<Connection> msc = new Connection(this, flags); ++ ++ nsresult rv = msc->initialize(aFileURL); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ msc.forget(_connection); + return NS_OK; + } + +@@ -885,67 +833,5 @@ Service::Observe(nsISupports *, const char *aTopic, const PRUnichar *) + return NS_OK; + } + +-//////////////////////////////////////////////////////////////////////////////// +-//// mozIStorageServiceQuotaManagement +- +-NS_IMETHODIMP +-Service::OpenDatabaseWithVFS(nsIFile *aDatabaseFile, +- const nsACString &aVFSName, +- mozIStorageConnection **_connection) +-{ +- NS_ENSURE_ARG(aDatabaseFile); +- +- // Always ensure that SQLITE_OPEN_CREATE is passed in for compatibility +- // reasons. +- int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE | +- SQLITE_OPEN_CREATE; +- nsRefPtr<Connection> msc = new Connection(this, flags); +- NS_ENSURE_TRUE(msc, NS_ERROR_OUT_OF_MEMORY); +- +- nsresult rv = msc->initialize(aDatabaseFile, +- PromiseFlatCString(aVFSName).get()); +- NS_ENSURE_SUCCESS(rv, rv); +- +- NS_ADDREF(*_connection = msc); +- return NS_OK; +-} +- +-NS_IMETHODIMP +-Service::SetQuotaForFilenamePattern(const nsACString &aPattern, +- int64_t aSizeLimit, +- mozIStorageQuotaCallback *aCallback, +- nsISupports *aUserData) +-{ +- NS_ENSURE_FALSE(aPattern.IsEmpty(), NS_ERROR_INVALID_ARG); +- +- nsAutoPtr<QuotaCallbackData> data; +- if (aSizeLimit && aCallback) { +- data = new QuotaCallbackData(aCallback, aUserData); +- } +- +- int rc = ::sqlite3_quota_set(PromiseFlatCString(aPattern).get(), +- aSizeLimit, QuotaCallbackData::Callback, +- data, QuotaCallbackData::Destroy); +- NS_ENSURE_TRUE(rc == SQLITE_OK, convertResultCode(rc)); +- +- data.forget(); +- return NS_OK; +-} +- +-NS_IMETHODIMP +-Service::UpdateQuotaInformationForFile(nsIFile *aFile) +-{ +- NS_ENSURE_ARG_POINTER(aFile); +- +- nsString path; +- nsresult rv = aFile->GetPath(path); +- NS_ENSURE_SUCCESS(rv, rv); +- +- int rc = ::sqlite3_quota_file(NS_ConvertUTF16toUTF8(path).get()); +- NS_ENSURE_TRUE(rc == SQLITE_OK, convertResultCode(rc)); +- +- return NS_OK; +-} +- + } // namespace storage + } // namespace mozilla +diff --git storage/src/mozStorageService.h storage/src/mozStorageService.h +index 21c1ff8..3f5a546 100644 +--- mozilla/storage/src/mozStorageService.h ++++ mozilla/storage/src/mozStorageService.h +@@ -15,7 +15,6 @@ + #include "mozilla/Mutex.h" + + #include "mozIStorageService.h" +-#include "mozIStorageServiceQuotaManagement.h" + + class nsIMemoryReporter; + class nsIMemoryMultiReporter; +@@ -28,7 +27,6 @@ namespace storage { + class Connection; + class Service : public mozIStorageService + , public nsIObserver +- , public mozIStorageServiceQuotaManagement + { + public: + /** +@@ -58,7 +56,6 @@ public: + NS_DECL_ISUPPORTS + NS_DECL_MOZISTORAGESERVICE + NS_DECL_NSIOBSERVER +- NS_DECL_MOZISTORAGESERVICEQUOTAMANAGEMENT + + /** + * Obtains an already AddRefed pointer to XPConnect. This is used by +diff --git toolkit/toolkit-makefiles.sh toolkit/toolkit-makefiles.sh +index 6a7d714..8f1bbe0 100644 +--- mozilla/toolkit/toolkit-makefiles.sh ++++ mozilla/toolkit/toolkit-makefiles.sh +@@ -68,6 +68,7 @@ MAKEFILES_dom=" + dom/plugins/base/Makefile + dom/plugins/ipc/Makefile + dom/power/Makefile ++ dom/quota/Makefile + dom/settings/Makefile + dom/sms/Makefile + dom/sms/interfaces/Makefile Added: trunk/www/firefox/files/patch-bug787804 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ trunk/www/firefox/files/patch-bug787804 Wed Jan 2 19:58:18 2013 (r1130) @@ -0,0 +1,3557 @@ +commit 74997f1 +Author: Jan Varga <jan.varga@gmail.com> +Date: Mon Dec 17 20:25:10 2012 +0100 + + Bug 787804 - Rewrite quota handling (eliminate test_quota.c). r=bent,asuth,vladan +--- + db/sqlite3/README.MOZILLA | 4 +- + db/sqlite3/src/sqlite.def | 1 + + db/sqlite3/src/test_quota.c | 2001 -------------------- + db/sqlite3/src/test_quota.h | 274 --- + dom/Makefile.in | 1 + + dom/dom-config.mk | 1 + + dom/file/FileStreamWrappers.cpp | 11 - + dom/file/LockedFile.cpp | 8 +- + dom/file/nsIFileStorage.h | 40 +- + dom/indexedDB/FileManager.cpp | 33 +- + dom/indexedDB/FileManager.h | 20 +- + dom/indexedDB/FileStream.cpp | 321 ---- + dom/indexedDB/FileStream.h | 140 -- + dom/indexedDB/IDBDatabase.cpp | 6 + + dom/indexedDB/IDBFactory.cpp | 28 +- + dom/indexedDB/IDBFactory.h | 8 +- + dom/indexedDB/IDBFileHandle.cpp | 25 +- + dom/indexedDB/IDBObjectStore.cpp | 10 +- + dom/indexedDB/IDBTransaction.cpp | 3 +- + dom/indexedDB/IndexedDatabaseInlines.h | 13 + + dom/indexedDB/IndexedDatabaseManager.cpp | 162 +- + dom/indexedDB/IndexedDatabaseManager.h | 11 +- + dom/indexedDB/Makefile.in | 2 - + dom/indexedDB/OpenDatabaseHelper.cpp | 104 +- + dom/indexedDB/OpenDatabaseHelper.h | 12 +- + dom/indexedDB/nsIStandardFileStream.idl | 60 - + dom/indexedDB/test/Makefile.in | 2 + + dom/indexedDB/test/file.js | 21 +- + dom/indexedDB/test/test_file_quota.html | 14 +- + dom/indexedDB/test/test_filehandle_quota.html | 5 +- + dom/quota/FileStreams.cpp | 123 ++ + dom/quota/FileStreams.h | 115 ++ + dom/quota/Makefile.in | 33 + + dom/quota/QuotaCommon.h | 23 + + dom/quota/QuotaManager.cpp | 294 +++ + dom/quota/QuotaManager.h | 147 ++ + layout/build/Makefile.in | 1 + + netwerk/base/src/Makefile.in | 1 + + netwerk/base/src/nsFileStreams.cpp | 103 +- + netwerk/base/src/nsFileStreams.h | 12 +- + storage/public/Makefile.in | 1 - + storage/public/mozIStorageService.idl | 13 +- + .../public/mozIStorageServiceQuotaManagement.idl | 99 - + storage/public/storage.h | 1 - + storage/src/TelemetryVFS.cpp | 35 +- + storage/src/mozStorageConnection.cpp | 85 +- + storage/src/mozStorageConnection.h | 27 +- + storage/src/mozStorageService.cpp | 168 +- + storage/src/mozStorageService.h | 3 - + toolkit/toolkit-makefiles.sh | 1 + + 50 files changed, 1239 insertions(+), 3387 deletions(-) + +diff --git dom/Makefile.in dom/Makefile.in +index 672e065..47cd253 100644 +--- dom/Makefile.in ++++ dom/Makefile.in +@@ -58,6 +58,7 @@ PARALLEL_DIRS += \ + media \ + messages \ + power \ ++ quota \ + settings \ + sms \ + mms \ +diff --git dom/dom-config.mk dom/dom-config.mk +index d0f46cc..1cf57ed 100644 +--- dom/dom-config.mk ++++ dom/dom-config.mk +@@ -8,6 +8,7 @@ DOM_SRCDIRS = \ + dom/encoding \ + dom/file \ + dom/power \ ++ dom/quota \ + dom/media \ + dom/network/src \ + dom/settings \ +diff --git dom/file/FileStreamWrappers.cpp dom/file/FileStreamWrappers.cpp +index 2283266..c4cf102 100644 +--- dom/file/FileStreamWrappers.cpp ++++ dom/file/FileStreamWrappers.cpp +@@ -8,7 +8,6 @@ + + #include "nsIFileStorage.h" + #include "nsISeekableStream.h" +-#include "nsIStandardFileStream.h" + #include "mozilla/Attributes.h" + + #include "FileHelper.h" +@@ -246,16 +245,6 @@ FileOutputStreamWrapper::Close() + nsresult rv = NS_OK; + + if (!mFirstTime) { +- // We must flush buffers of the stream on the same thread on which we wrote +- // some data. +- nsCOMPtr<nsIStandardFileStream> sstream = do_QueryInterface(mFileStream); +- if (sstream) { +- rv = sstream->FlushBuffers(); +- if (NS_FAILED(rv)) { +- NS_WARNING("Failed to flush buffers of the stream!"); +- } +- } +- + NS_ASSERTION(PR_GetCurrentThread() == mWriteThread, + "Unsetting thread locals on wrong thread!"); + mFileHelper->mFileStorage->UnsetThreadLocals(); +diff --git dom/file/LockedFile.cpp dom/file/LockedFile.cpp +index 0fca730..926df91 100644 +--- dom/file/LockedFile.cpp ++++ dom/file/LockedFile.cpp +@@ -953,10 +953,10 @@ FinishHelper::Run() + } + + for (uint32_t index = 0; index < mParallelStreams.Length(); index++) { +- nsCOMPtr<nsIOutputStream> ostream = ++ nsCOMPtr<nsIInputStream> stream = + do_QueryInterface(mParallelStreams[index]); + +- if (NS_FAILED(ostream->Close())) { ++ if (NS_FAILED(stream->Close())) { + NS_WARNING("Failed to close stream!"); + } + +@@ -964,9 +964,9 @@ FinishHelper::Run() + } + + if (mStream) { +- nsCOMPtr<nsIOutputStream> ostream = do_QueryInterface(mStream); ++ nsCOMPtr<nsIInputStream> stream = do_QueryInterface(mStream); + +- if (NS_FAILED(ostream->Close())) { ++ if (NS_FAILED(stream->Close())) { + NS_WARNING("Failed to close stream!"); + } + +diff --git dom/file/nsIFileStorage.h dom/file/nsIFileStorage.h +index 92bb608..e985f0a 100644 +--- dom/file/nsIFileStorage.h ++++ dom/file/nsIFileStorage.h +@@ -10,14 +10,17 @@ + #include "nsISupports.h" + + #define NS_FILESTORAGE_IID \ +- {0xbba9c2ff, 0x85c9, 0x47c1, \ +- { 0xaf, 0xce, 0x0a, 0x7e, 0x6f, 0x21, 0x50, 0x95 } } ++ {0xa0801944, 0x2f1c, 0x4203, \ ++ { 0x9c, 0xaa, 0xaa, 0x47, 0xe0, 0x0c, 0x67, 0x92 } } + + class nsIFileStorage : public nsISupports + { + public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_FILESTORAGE_IID) + ++ virtual const nsACString& ++ StorageOrigin() = 0; ++ + virtual nsISupports* + StorageId() = 0; + +@@ -36,20 +39,23 @@ public: + + NS_DEFINE_STATIC_IID_ACCESSOR(nsIFileStorage, NS_FILESTORAGE_IID) + +-#define NS_DECL_NSIFILESTORAGE \ +- virtual nsISupports* \ +- StorageId(); \ +- \ +- virtual bool \ +- IsStorageInvalidated(); \ +- \ +- virtual bool \ +- IsStorageShuttingDown(); \ +- \ +- virtual void \ +- SetThreadLocals(); \ +- \ +- virtual void \ +- UnsetThreadLocals(); ++#define NS_DECL_NSIFILESTORAGE \ ++ virtual const nsACString& \ ++ StorageOrigin() MOZ_OVERRIDE; \ ++ \ ++ virtual nsISupports* \ ++ StorageId() MOZ_OVERRIDE; \ ++ \ ++ virtual bool \ ++ IsStorageInvalidated() MOZ_OVERRIDE; \ ++ \ ++ virtual bool \ ++ IsStorageShuttingDown() MOZ_OVERRIDE; \ ++ \ ++ virtual void \ ++ SetThreadLocals() MOZ_OVERRIDE; \ ++ \ ++ virtual void \ ++ UnsetThreadLocals() MOZ_OVERRIDE; + + #endif // nsIFileStorage_h__ +diff --git dom/indexedDB/FileManager.cpp dom/indexedDB/FileManager.cpp +index 9db56e8..4ed6e9e 100644 +--- dom/indexedDB/FileManager.cpp ++++ dom/indexedDB/FileManager.cpp +@@ -7,8 +7,8 @@ + #include "FileManager.h" + + #include "mozIStorageConnection.h" +-#include "mozIStorageServiceQuotaManagement.h" + #include "mozIStorageStatement.h" ++#include "nsIInputStream.h" + #include "nsISimpleEnumerator.h" + + #include "mozStorageCID.h" +@@ -18,6 +18,8 @@ + #include "IndexedDatabaseManager.h" + #include "OpenDatabaseHelper.h" + ++#include "IndexedDatabaseInlines.h" ++ + #define JOURNAL_DIRECTORY_NAME "journals" + + USING_INDEXEDDB_NAMESPACE +@@ -262,13 +264,11 @@ FileManager::GetFileForId(nsIFile* aDirectory, int64_t aId) + + // static + nsresult +-FileManager::InitDirectory(mozIStorageServiceQuotaManagement* aService, +- nsIFile* aDirectory, ++FileManager::InitDirectory(nsIFile* aDirectory, + nsIFile* aDatabaseFile, +- FactoryPrivilege aPrivilege) ++ const nsACString& aOrigin) + { + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); +- NS_ASSERTION(aService, "Null service!"); + NS_ASSERTION(aDirectory, "Null directory!"); + NS_ASSERTION(aDatabaseFile, "Null database file!"); + +@@ -310,8 +310,8 @@ FileManager::InitDirectory(mozIStorageServiceQuotaManagement* aService, + + if (hasElements) { + nsCOMPtr<mozIStorageConnection> connection; +- rv = OpenDatabaseHelper::CreateDatabaseConnection( +- NullString(), aDatabaseFile, aDirectory, getter_AddRefs(connection)); ++ rv = OpenDatabaseHelper::CreateDatabaseConnection(aDatabaseFile, ++ aDirectory, NullString(), aOrigin, getter_AddRefs(connection)); + NS_ENSURE_SUCCESS(rv, rv); + + mozStorageTransaction transaction(connection, false); +@@ -377,12 +377,17 @@ FileManager::InitDirectory(mozIStorageServiceQuotaManagement* aService, + } + } + +- if (aPrivilege == Chrome) { +- return NS_OK; +- } ++ return NS_OK; ++} ++ ++// static ++nsresult ++FileManager::GetUsage(nsIFile* aDirectory, uint64_t* aUsage) ++{ ++ uint64_t usage = 0; + + nsCOMPtr<nsISimpleEnumerator> entries; +- rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries)); ++ nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries)); + NS_ENSURE_SUCCESS(rv, rv); + + bool hasMore; +@@ -402,9 +407,13 @@ FileManager::InitDirectory(mozIStorageServiceQuotaManagement* aService, + continue; + } + +- rv = aService->UpdateQuotaInformationForFile(file); ++ int64_t fileSize; ++ rv = file->GetFileSize(&fileSize); + NS_ENSURE_SUCCESS(rv, rv); ++ ++ IncrementUsage(&usage, uint64_t(fileSize)); + } + ++ *aUsage = usage; + return NS_OK; + } +diff --git dom/indexedDB/FileManager.h dom/indexedDB/FileManager.h +index 2c72d0a..370d4a8 100644 +--- dom/indexedDB/FileManager.h ++++ dom/indexedDB/FileManager.h +@@ -24,10 +24,10 @@ class FileManager + friend class FileInfo; + + public: +- FileManager(const nsACString& aOrigin, ++ FileManager(const nsACString& aOrigin, FactoryPrivilege aPrivilege, + const nsAString& aDatabaseName) +- : mOrigin(aOrigin), mDatabaseName(aDatabaseName), mLastFileId(0), +- mInvalidated(false) ++ : mOrigin(aOrigin), mPrivilege(aPrivilege), mDatabaseName(aDatabaseName), ++ mLastFileId(0), mInvalidated(false) + { } + + ~FileManager() +@@ -40,6 +40,11 @@ public: + return mOrigin; + } + ++ const FactoryPrivilege& Privilege() const ++ { ++ return mPrivilege; ++ } ++ + const nsAString& DatabaseName() const + { + return mDatabaseName; +@@ -68,12 +73,15 @@ public: + static already_AddRefed<nsIFile> GetFileForId(nsIFile* aDirectory, + int64_t aId); + +- static nsresult InitDirectory(mozIStorageServiceQuotaManagement* aService, +- nsIFile* aDirectory, nsIFile* aDatabaseFile, +- FactoryPrivilege aPrivilege); ++ static nsresult InitDirectory(nsIFile* aDirectory, ++ nsIFile* aDatabaseFile, ++ const nsACString& aOrigin); ++ ++ static nsresult GetUsage(nsIFile* aDirectory, uint64_t* aUsage); + + private: + nsCString mOrigin; ++ FactoryPrivilege mPrivilege; + nsString mDatabaseName; + + nsString mDirectoryPath; +diff --git dom/indexedDB/FileStream.cpp dom/indexedDB/FileStream.cpp +deleted file mode 100644 +index dddf5d5..0000000 +--- dom/indexedDB/FileStream.cpp ++++ /dev/null +@@ -1,321 +0,0 @@ +-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +-/* vim: set ts=2 et sw=2 tw=80: */ +-/* This Source Code Form is subject to the terms of the Mozilla Public +- * License, v. 2.0. If a copy of the MPL was not distributed with this file, +- * You can obtain one at http://mozilla.org/MPL/2.0/. */ +- +-#include "FileStream.h" +- +-#include "nsIFile.h" +- +-#include "nsThreadUtils.h" +-#include "test_quota.h" +- +-USING_INDEXEDDB_NAMESPACE +- +-NS_IMPL_THREADSAFE_ADDREF(FileStream) +-NS_IMPL_THREADSAFE_RELEASE(FileStream) +- +-NS_INTERFACE_MAP_BEGIN(FileStream) +- NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStandardFileStream) +- NS_INTERFACE_MAP_ENTRY(nsISeekableStream) +- NS_INTERFACE_MAP_ENTRY(nsIInputStream) +- NS_INTERFACE_MAP_ENTRY(nsIOutputStream) +- NS_INTERFACE_MAP_ENTRY(nsIStandardFileStream) +- NS_INTERFACE_MAP_ENTRY(nsIFileMetadata) +-NS_INTERFACE_MAP_END +- +-NS_IMETHODIMP +-FileStream::Seek(int32_t aWhence, int64_t aOffset) +-{ +- // TODO: Add support for 64 bit file sizes, bug 752431 +- NS_ENSURE_TRUE(aOffset <= INT32_MAX, NS_ERROR_INVALID_ARG); +- +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- int whence; +- switch (aWhence) { +- case nsISeekableStream::NS_SEEK_SET: +- whence = SEEK_SET; +- break; +- case nsISeekableStream::NS_SEEK_CUR: +- whence = SEEK_CUR; +- break; +- case nsISeekableStream::NS_SEEK_END: +- whence = SEEK_END; +- break; +- default: +- return NS_ERROR_INVALID_ARG; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- int rc = sqlite3_quota_fseek(mQuotaFile, aOffset, whence); +- NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR); +- +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::Tell(int64_t* aResult) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- long rc = sqlite3_quota_ftell(mQuotaFile); +- NS_ENSURE_TRUE(rc >= 0, NS_BASE_STREAM_OSERROR); +- +- *aResult = rc; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::SetEOF() +-{ +- int64_t pos; +- nsresult rv = Tell(&pos); +- NS_ENSURE_SUCCESS(rv, rv); +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- int rc = sqlite3_quota_ftruncate(mQuotaFile, pos); +- NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR); +- +- return NS_OK; +-} +- +- +-NS_IMETHODIMP +-FileStream::Close() +-{ +- CleanUpOpen(); +- +- if (mQuotaFile) { +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- int rc = sqlite3_quota_fclose(mQuotaFile); +- mQuotaFile = nullptr; +- +- NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR); +- } +- +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::Available(uint64_t* aResult) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- long rc = sqlite3_quota_file_available(mQuotaFile); +- NS_ENSURE_TRUE(rc >= 0, NS_BASE_STREAM_OSERROR); +- +- *aResult = rc; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::Read(char* aBuf, uint32_t aCount, uint32_t* aResult) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- size_t bytesRead = sqlite3_quota_fread(aBuf, 1, aCount, mQuotaFile); +- if (bytesRead < aCount && sqlite3_quota_ferror(mQuotaFile)) { +- return NS_BASE_STREAM_OSERROR; +- } +- +- *aResult = bytesRead; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, +- uint32_t aCount, uint32_t* aResult) +-{ +- NS_NOTREACHED("Don't call me!"); +- return NS_ERROR_NOT_IMPLEMENTED; +-} +- +-NS_IMETHODIMP +-FileStream::IsNonBlocking(bool *aNonBlocking) +-{ +- *aNonBlocking = false; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::Write(const char* aBuf, uint32_t aCount, uint32_t *aResult) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- size_t bytesWritten = sqlite3_quota_fwrite(aBuf, 1, aCount, mQuotaFile); +- if (bytesWritten < aCount) { +- return NS_BASE_STREAM_OSERROR; +- } +- +- *aResult = bytesWritten; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::Flush() +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- int rc = sqlite3_quota_fflush(mQuotaFile, 1); +- NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR); +- +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::WriteFrom(nsIInputStream *inStr, uint32_t count, uint32_t *_retval) +-{ +- return NS_ERROR_NOT_IMPLEMENTED; +-} +- +-NS_IMETHODIMP +-FileStream::WriteSegments(nsReadSegmentFun reader, void * closure, uint32_t count, uint32_t *_retval) +-{ +- NS_NOTREACHED("Don't call me!"); +- return NS_ERROR_NOT_IMPLEMENTED; +-} +- +-NS_IMETHODIMP +-FileStream::Init(nsIFile* aFile, const nsAString& aMode, int32_t aFlags) +-{ +- NS_ASSERTION(!mQuotaFile && !mDeferredOpen, "Already initialized!"); +- +- nsresult rv = aFile->GetPath(mFilePath); +- NS_ENSURE_SUCCESS(rv, rv); +- +- mMode = aMode; +- mFlags = aFlags; +- +- if (mFlags & nsIStandardFileStream::FLAGS_DEFER_OPEN) { +- mDeferredOpen = true; +- return NS_OK; +- } +- +- return DoOpen(); +-} +- +-NS_IMETHODIMP +-FileStream::GetSize(int64_t* _retval) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- // TODO: Use sqlite3_quota_file_size() here, bug 760783 +- int64_t rc = sqlite3_quota_file_truesize(mQuotaFile); +- +- NS_ASSERTION(rc >= 0, "The file is not under quota management!"); +- +- *_retval = rc; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::GetLastModified(int64_t* _retval) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- time_t mtime; +- int rc = sqlite3_quota_file_mtime(mQuotaFile, &mtime); +- NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR); +- +- *_retval = mtime * PR_MSEC_PER_SEC; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::FlushBuffers() +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- int rc = sqlite3_quota_fflush(mQuotaFile, 0); +- NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR); +- +- return NS_OK; +-} +- +-nsresult +-FileStream::DoOpen() +-{ +- NS_ASSERTION(!mFilePath.IsEmpty(), "Must have a file path"); +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- quota_FILE* quotaFile = +- sqlite3_quota_fopen(NS_ConvertUTF16toUTF8(mFilePath).get(), +- NS_ConvertUTF16toUTF8(mMode).get()); +- +- CleanUpOpen(); +- +- if (!quotaFile) { +- return NS_BASE_STREAM_OSERROR; +- } +- +- mQuotaFile = quotaFile; +- +- return NS_OK; +-} +diff --git dom/indexedDB/FileStream.h dom/indexedDB/FileStream.h +deleted file mode 100644 +index 09648b1..0000000 +--- dom/indexedDB/FileStream.h ++++ /dev/null +@@ -1,140 +0,0 @@ +-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +-/* vim: set ts=2 et sw=2 tw=80: */ +-/* This Source Code Form is subject to the terms of the Mozilla Public +- * License, v. 2.0. If a copy of the MPL was not distributed with this file, +- * You can obtain one at http://mozilla.org/MPL/2.0/. */ +- +-#ifndef mozilla_dom_indexeddb_filestream_h__ +-#define mozilla_dom_indexeddb_filestream_h__ +- +-#include "IndexedDatabase.h" +- +-#include "nsIFileStreams.h" +-#include "nsIInputStream.h" +-#include "nsIOutputStream.h" +-#include "nsISeekableStream.h" +-#include "nsIStandardFileStream.h" +- +-class nsIFile; +-struct quota_FILE; +- +-BEGIN_INDEXEDDB_NAMESPACE +- +-class FileStream : public nsISeekableStream, +- public nsIInputStream, +- public nsIOutputStream, +- public nsIStandardFileStream, +- public nsIFileMetadata +-{ +-public: +- FileStream() +- : mFlags(0), +- mDeferredOpen(false), +- mQuotaFile(nullptr) +- { } +- +- virtual ~FileStream() +- { +- Close(); +- } +- +- NS_DECL_ISUPPORTS +- NS_DECL_NSISEEKABLESTREAM +- NS_DECL_NSISTANDARDFILESTREAM +- NS_DECL_NSIFILEMETADATA +- +- // nsIInputStream +- NS_IMETHOD +- Close(); +- +- NS_IMETHOD +- Available(uint64_t* _retval); +- +- NS_IMETHOD +- Read(char* aBuf, uint32_t aCount, uint32_t* _retval); +- +- NS_IMETHOD +- ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, uint32_t aCount, +- uint32_t* _retval); +- +- NS_IMETHOD +- IsNonBlocking(bool* _retval); +- +- // nsIOutputStream +- +- // Close() already declared +- +- NS_IMETHOD +- Flush(); +- +- NS_IMETHOD +- Write(const char* aBuf, uint32_t aCount, uint32_t* _retval); +- +- NS_IMETHOD +- WriteFrom(nsIInputStream* aFromStream, uint32_t aCount, uint32_t* _retval); +- +- NS_IMETHOD +- WriteSegments(nsReadSegmentFun aReader, void* aClosure, uint32_t aCount, +- uint32_t* _retval); +- +- // IsNonBlocking() already declared +- +-protected: +- /** +- * Cleans up data prepared in Init. +- */ +- void +- CleanUpOpen() +- { +- mFilePath.Truncate(); +- mDeferredOpen = false; +- } +- +- /** +- * Open the file. This is called either from Init +- * or from DoPendingOpen (if FLAGS_DEFER_OPEN is used when initializing this +- * stream). The default behavior of DoOpen is to open the file and save the +- * file descriptor. +- */ +- virtual nsresult +- DoOpen(); +- +- /** +- * If there is a pending open, do it now. It's important for this to be +- * inlined since we do it in almost every stream API call. +- */ +- nsresult +- DoPendingOpen() +- { +- if (!mDeferredOpen) { +- return NS_OK; +- } +- +- return DoOpen(); +- } +- +- /** +- * Data we need to do an open. +- */ +- nsString mFilePath; +- nsString mMode; +- +- /** +- * Flags describing our behavior. See the IDL file for possible values. +- */ +- int32_t mFlags; +- +- /** +- * Whether we have a pending open (see FLAGS_DEFER_OPEN in the IDL file). +- */ +- bool mDeferredOpen; +- +- /** +- * File descriptor for opened file. +- */ +- quota_FILE* mQuotaFile; +-}; +- +-END_INDEXEDDB_NAMESPACE +- +-#endif // mozilla_dom_indexeddb_filestream_h__ +diff --git dom/indexedDB/IDBDatabase.cpp dom/indexedDB/IDBDatabase.cpp +index 63500b0..8842daf 100644 +--- dom/indexedDB/IDBDatabase.cpp ++++ dom/indexedDB/IDBDatabase.cpp +@@ -779,6 +779,12 @@ IDBDatabase::Close() + return NS_OK; + } + ++const nsACString& ++IDBDatabase::StorageOrigin() ++{ ++ return Origin(); ++} ++ + nsISupports* + IDBDatabase::StorageId() + { +diff --git dom/indexedDB/IDBFactory.cpp dom/indexedDB/IDBFactory.cpp +index 1007df1..c1f573e 100644 +--- dom/indexedDB/IDBFactory.cpp ++++ dom/indexedDB/IDBFactory.cpp +@@ -253,8 +253,26 @@ IDBFactory::Create(ContentParent* aContentParent, + } + + // static ++already_AddRefed<nsIFileURL> ++IDBFactory::GetDatabaseFileURL(nsIFile* aDatabaseFile, const nsACString& aOrigin) ++{ ++ nsCOMPtr<nsIURI> uri; ++ nsresult rv = NS_NewFileURI(getter_AddRefs(uri), aDatabaseFile); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ ++ nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(uri); ++ NS_ASSERTION(fileUrl, "This should always succeed!"); ++ ++ rv = fileUrl->SetQuery(NS_LITERAL_CSTRING("origin=") + aOrigin); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ ++ return fileUrl.forget(); ++} ++ ++// static + already_AddRefed<mozIStorageConnection> +-IDBFactory::GetConnection(const nsAString& aDatabaseFilePath) ++IDBFactory::GetConnection(const nsAString& aDatabaseFilePath, ++ const nsACString& aOrigin) + { + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); + NS_ASSERTION(StringEndsWith(aDatabaseFilePath, NS_LITERAL_STRING(".sqlite")), +@@ -271,13 +289,15 @@ IDBFactory::GetConnection(const nsAString& aDatabaseFilePath) + NS_ENSURE_SUCCESS(rv, nullptr); + NS_ENSURE_TRUE(exists, nullptr); + +- nsCOMPtr<mozIStorageServiceQuotaManagement> ss = ++ nsCOMPtr<nsIFileURL> dbFileUrl = GetDatabaseFileURL(dbFile, aOrigin); ++ NS_ENSURE_TRUE(dbFileUrl, nullptr); ++ ++ nsCOMPtr<mozIStorageService> ss = + do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID); + NS_ENSURE_TRUE(ss, nullptr); + + nsCOMPtr<mozIStorageConnection> connection; +- rv = ss->OpenDatabaseWithVFS(dbFile, NS_LITERAL_CSTRING("quota"), +- getter_AddRefs(connection)); ++ rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(connection)); + NS_ENSURE_SUCCESS(rv, nullptr); + + // Turn on foreign key constraints and recursive triggers. +diff --git dom/indexedDB/IDBFactory.h dom/indexedDB/IDBFactory.h +index d5461f7..49dad42 100644 +--- dom/indexedDB/IDBFactory.h ++++ dom/indexedDB/IDBFactory.h +@@ -15,6 +15,8 @@ + #include "nsCycleCollectionParticipant.h" + + class nsIAtom; ++class nsIFile; ++class nsIFileURL; + class nsPIDOMWindow; + + namespace mozilla { +@@ -75,8 +77,12 @@ public: + static nsresult Create(ContentParent* aContentParent, + IDBFactory** aFactory); + ++ static already_AddRefed<nsIFileURL> ++ GetDatabaseFileURL(nsIFile* aDatabaseFile, const nsACString& aOrigin); ++ + static already_AddRefed<mozIStorageConnection> +- GetConnection(const nsAString& aDatabaseFilePath); ++ GetConnection(const nsAString& aDatabaseFilePath, ++ const nsACString& aOrigin); + + static nsresult + LoadDatabaseInformation(mozIStorageConnection* aConnection, +diff --git dom/indexedDB/IDBFileHandle.cpp dom/indexedDB/IDBFileHandle.cpp +index e0340ff..f71fd56 100644 +--- dom/indexedDB/IDBFileHandle.cpp ++++ dom/indexedDB/IDBFileHandle.cpp +@@ -6,15 +6,14 @@ + + #include "IDBFileHandle.h" + +-#include "nsIStandardFileStream.h" +- + #include "mozilla/dom/file/File.h" ++#include "mozilla/dom/quota/FileStreams.h" + #include "nsDOMClassInfoID.h" + +-#include "FileStream.h" + #include "IDBDatabase.h" + + USING_INDEXEDDB_NAMESPACE ++USING_QUOTA_NAMESPACE + + namespace { + +@@ -68,22 +67,22 @@ IDBFileHandle::Create(IDBDatabase* aDatabase, + already_AddRefed<nsISupports> + IDBFileHandle::CreateStream(nsIFile* aFile, bool aReadOnly) + { +- nsRefPtr<FileStream> stream = new FileStream(); ++ const nsACString& origin = mFileStorage->StorageOrigin(); ++ ++ nsCOMPtr<nsISupports> result; + +- nsString streamMode; + if (aReadOnly) { +- streamMode.AssignLiteral("rb"); ++ nsRefPtr<FileInputStream> stream = FileInputStream::Create( ++ origin, aFile, -1, -1, nsIFileInputStream::DEFER_OPEN); ++ result = NS_ISUPPORTS_CAST(nsIFileInputStream*, stream); + } + else { +- streamMode.AssignLiteral("r+b"); ++ nsRefPtr<FileStream> stream = FileStream::Create( ++ origin, aFile, -1, -1, nsIFileStream::DEFER_OPEN); ++ result = NS_ISUPPORTS_CAST(nsIFileStream*, stream); + } ++ NS_ENSURE_TRUE(result, nullptr); + +- nsresult rv = stream->Init(aFile, streamMode, +- nsIStandardFileStream::FLAGS_DEFER_OPEN); +- NS_ENSURE_SUCCESS(rv, nullptr); +- +- nsCOMPtr<nsISupports> result = +- NS_ISUPPORTS_CAST(nsIStandardFileStream*, stream); + return result.forget(); + } + +diff --git dom/indexedDB/IDBObjectStore.cpp dom/indexedDB/IDBObjectStore.cpp +index 746d473..1f16d26 100644 +--- dom/indexedDB/IDBObjectStore.cpp ++++ dom/indexedDB/IDBObjectStore.cpp +@@ -17,6 +17,7 @@ + #include "mozilla/dom/ContentParent.h" + #include "mozilla/dom/StructuredCloneTags.h" + #include "mozilla/dom/ipc/Blob.h" ++#include "mozilla/dom/quota/FileStreams.h" + #include "mozilla/storage.h" + #include "nsContentUtils.h" + #include "nsDOMClassInfo.h" +@@ -27,10 +28,8 @@ + #include "nsServiceManagerUtils.h" + #include "nsThreadUtils.h" + #include "snappy/snappy.h" +-#include "test_quota.h" + + #include "AsyncConnectionHelper.h" +-#include "FileStream.h" + #include "IDBCursor.h" + #include "IDBEvents.h" + #include "IDBFileHandle.h" +@@ -51,6 +50,7 @@ + USING_INDEXEDDB_NAMESPACE + using namespace mozilla::dom; + using namespace mozilla::dom::indexedDB::ipc; ++using mozilla::dom::quota::FileOutputStream; + + namespace { + +@@ -2734,9 +2734,9 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection) + nativeFile = fileManager->GetFileForId(directory, id); + NS_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- nsRefPtr<FileStream> outputStream = new FileStream(); +- rv = outputStream->Init(nativeFile, NS_LITERAL_STRING("wb"), 0); +- NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); ++ nsRefPtr<FileOutputStream> outputStream = FileOutputStream::Create( ++ mObjectStore->Transaction()->Database()->Origin(), nativeFile); ++ NS_ENSURE_TRUE(outputStream, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + rv = CopyData(inputStream, outputStream); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); +diff --git dom/indexedDB/IDBTransaction.cpp dom/indexedDB/IDBTransaction.cpp +index fcef7cc..a5345e2 100644 +--- dom/indexedDB/IDBTransaction.cpp ++++ dom/indexedDB/IDBTransaction.cpp +@@ -352,7 +352,8 @@ IDBTransaction::GetOrCreateConnection(mozIStorageConnection** aResult) + + if (!mConnection) { + nsCOMPtr<mozIStorageConnection> connection = +- IDBFactory::GetConnection(mDatabase->FilePath()); ++ IDBFactory::GetConnection(mDatabase->FilePath(), ++ mDatabase->Origin()); + NS_ENSURE_TRUE(connection, NS_ERROR_FAILURE); + + nsresult rv; +diff --git dom/indexedDB/IndexedDatabaseInlines.h dom/indexedDB/IndexedDatabaseInlines.h +index 62e65d6..f27d60c 100644 +--- dom/indexedDB/IndexedDatabaseInlines.h ++++ dom/indexedDB/IndexedDatabaseInlines.h +@@ -79,4 +79,17 @@ AppendConditionClause(const nsACString& aColumnName, + aResult += NS_LITERAL_CSTRING(" :") + aArgName; + } + ++inline void ++IncrementUsage(uint64_t* aUsage, uint64_t aDelta) ++{ ++ // Watch for overflow! ++ if ((UINT64_MAX - *aUsage) < aDelta) { ++ NS_WARNING("Usage exceeds the maximum!"); ++ *aUsage = UINT64_MAX; ++ } ++ else { ++ *aUsage += aDelta; ++ } ++} ++ + END_INDEXEDDB_NAMESPACE +diff --git dom/indexedDB/IndexedDatabaseManager.cpp dom/indexedDB/IndexedDatabaseManager.cpp +index e4ad647..88f09da 100644 +--- dom/indexedDB/IndexedDatabaseManager.cpp ++++ dom/indexedDB/IndexedDatabaseManager.cpp +@@ -22,6 +22,7 @@ + #include "nsITimer.h" + + #include "mozilla/dom/file/FileService.h" ++#include "mozilla/dom/quota/QuotaManager.h" + #include "mozilla/dom/TabContext.h" + #include "mozilla/LazyIdleThread.h" + #include "mozilla/Preferences.h" +@@ -36,7 +37,6 @@ + #include "nsThreadUtils.h" + #include "nsXPCOM.h" + #include "nsXPCOMPrivate.h" +-#include "test_quota.h" + #include "xpcpublic.h" + + #include "AsyncConnectionHelper.h" +@@ -48,6 +48,8 @@ + #include "OpenDatabaseHelper.h" + #include "TransactionThreadPool.h" + ++#include "IndexedDatabaseInlines.h" ++ + // The amount of time, in milliseconds, that our IO thread will stay alive + // after the last event it processes. + #define DEFAULT_THREAD_TIMEOUT_MS 30000 +@@ -70,6 +72,7 @@ using namespace mozilla::services; + using namespace mozilla::dom; + using mozilla::Preferences; + using mozilla::dom::file::FileService; ++using mozilla::dom::quota::QuotaManager; + + static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID); + +@@ -103,29 +106,6 @@ GetDatabaseBaseFilename(const nsAString& aFilename, + return true; + } + +-class QuotaCallback MOZ_FINAL : public mozIStorageQuotaCallback +-{ +-public: +- NS_DECL_ISUPPORTS +- +- NS_IMETHOD +- QuotaExceeded(const nsACString& aFilename, +- int64_t aCurrentSizeLimit, +- int64_t aCurrentTotalSize, +- nsISupports* aUserData, +- int64_t* _retval) +- { +- if (IndexedDatabaseManager::QuotaIsLifted()) { +- *_retval = 0; +- return NS_OK; +- } +- +- return NS_ERROR_FAILURE; +- } +-}; +- +-NS_IMPL_THREADSAFE_ISUPPORTS1(QuotaCallback, mozIStorageQuotaCallback) +- + // Adds all databases in the hash to the given array. + template <class T> + PLDHashOperator +@@ -440,8 +420,8 @@ IndexedDatabaseManager::GetOrCreate() + NS_LITERAL_CSTRING("IndexedDB I/O"), + LazyIdleThread::ManualShutdown); + +- // We need one quota callback object to hand to SQLite. +- instance->mQuotaCallbackSingleton = new QuotaCallback(); ++ // Make sure that the quota manager is up. ++ NS_ENSURE_TRUE(QuotaManager::GetOrCreate(), nullptr); + + // Make a timer here to avoid potential failures later. We don't actually + // initialize the timer until shutdown. +@@ -996,37 +976,15 @@ IndexedDatabaseManager::EnsureOriginIsInitialized(const nsACString& aOrigin, + return NS_OK; + } + +- // First figure out the filename pattern we'll use. +- nsCOMPtr<nsIFile> patternFile; +- rv = directory->Clone(getter_AddRefs(patternFile)); +- NS_ENSURE_SUCCESS(rv, rv); +- +- rv = patternFile->Append(NS_LITERAL_STRING("*")); +- NS_ENSURE_SUCCESS(rv, rv); +- +- nsString pattern; +- rv = patternFile->GetPath(pattern); +- NS_ENSURE_SUCCESS(rv, rv); +- +- // Now tell SQLite to start tracking this pattern for content. +- nsCOMPtr<mozIStorageServiceQuotaManagement> ss = +- do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID); +- NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE); +- +- if (aPrivilege != Chrome) { +- rv = ss->SetQuotaForFilenamePattern(NS_ConvertUTF16toUTF8(pattern), +- GetIndexedDBQuotaMB() * 1024 * 1024, +- mQuotaCallbackSingleton, nullptr); +- NS_ENSURE_SUCCESS(rv, rv); +- } +- + // We need to see if there are any files in the directory already. If they + // are database files then we need to cleanup stored files (if it's needed) +- // and also tell SQLite about all of them. ++ // and also initialize the quota. + + nsAutoTArray<nsString, 20> subdirsToProcess; + nsAutoTArray<nsCOMPtr<nsIFile> , 20> unknownFiles; + ++ uint64_t usage = 0; ++ + nsTHashtable<nsStringHashKey> validSubdirs; + validSubdirs.Init(20); + +@@ -1068,20 +1026,28 @@ IndexedDatabaseManager::EnsureOriginIsInitialized(const nsACString& aOrigin, + continue; + } + +- nsCOMPtr<nsIFile> fileManagerDirectory; +- rv = directory->Clone(getter_AddRefs(fileManagerDirectory)); ++ nsCOMPtr<nsIFile> fmDirectory; ++ rv = directory->Clone(getter_AddRefs(fmDirectory)); + NS_ENSURE_SUCCESS(rv, rv); + +- rv = fileManagerDirectory->Append(dbBaseFilename); ++ rv = fmDirectory->Append(dbBaseFilename); + NS_ENSURE_SUCCESS(rv, rv); + +- rv = FileManager::InitDirectory(ss, fileManagerDirectory, file, +- aPrivilege); ++ rv = FileManager::InitDirectory(fmDirectory, file, aOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + if (aPrivilege != Chrome) { +- rv = ss->UpdateQuotaInformationForFile(file); ++ uint64_t fileUsage; ++ rv = FileManager::GetUsage(fmDirectory, &fileUsage); + NS_ENSURE_SUCCESS(rv, rv); ++ ++ IncrementUsage(&usage, fileUsage); ++ ++ int64_t fileSize; ++ rv = file->GetFileSize(&fileSize); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ IncrementUsage(&usage, uint64_t(fileSize)); + } + + validSubdirs.PutEntry(dbBaseFilename); +@@ -1117,12 +1083,39 @@ IndexedDatabaseManager::EnsureOriginIsInitialized(const nsACString& aOrigin, + } + } + ++ if (aPrivilege != Chrome) { ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ quotaManager->InitQuotaForOrigin(aOrigin, GetIndexedDBQuotaMB(), usage); ++ } ++ + mInitializedOrigins.AppendElement(aOrigin); + + NS_ADDREF(*aDirectory = directory); + return NS_OK; + } + ++void ++IndexedDatabaseManager::UninitializeOriginsByPattern( ++ const nsACString& aPattern) ++{ ++#ifdef DEBUG ++ { ++ bool correctThread; ++ NS_ASSERTION(NS_SUCCEEDED(mIOThread->IsOnCurrentThread(&correctThread)) && ++ correctThread, ++ "Running on the wrong thread!"); ++ } ++#endif ++ ++ for (int32_t i = mInitializedOrigins.Length() - 1; i >= 0; i--) { ++ if (PatternMatchesOrigin(aPattern, mInitializedOrigins[i])) { ++ mInitializedOrigins.RemoveElementAt(i); ++ } ++ } ++} ++ + bool + IndexedDatabaseManager::QuotaIsLiftedInternal() + { +@@ -1250,16 +1243,14 @@ IndexedDatabaseManager::GetFileManager(const nsACString& aOrigin, + } + + void +-IndexedDatabaseManager::AddFileManager(const nsACString& aOrigin, +- const nsAString& aDatabaseName, +- FileManager* aFileManager) ++IndexedDatabaseManager::AddFileManager(FileManager* aFileManager) + { + NS_ASSERTION(aFileManager, "Null file manager!"); + + nsTArray<nsRefPtr<FileManager> >* array; +- if (!mFileManagers.Get(aOrigin, &array)) { ++ if (!mFileManagers.Get(aFileManager->Origin(), &array)) { + array = new nsTArray<nsRefPtr<FileManager> >(); +- mFileManagers.Put(aOrigin, array); ++ mFileManagers.Put(aFileManager->Origin(), array); + } + + array->AppendElement(aFileManager); +@@ -1783,6 +1774,13 @@ OriginClearRunnable::DeleteFiles(IndexedDatabaseManager* aManager) + // correctly... + NS_ERROR("Failed to remove directory!"); + } ++ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ quotaManager->RemoveQuotaForPattern(mOriginOrPattern); ++ ++ aManager->UninitializeOriginsByPattern(mOriginOrPattern); + } + } + +@@ -1880,19 +1878,6 @@ IndexedDatabaseManager::AsyncUsageRunnable::Cancel() + } + } + +-inline void +-IncrementUsage(uint64_t* aUsage, uint64_t aDelta) +-{ +- // Watch for overflow! +- if ((INT64_MAX - *aUsage) <= aDelta) { +- NS_WARNING("Database sizes exceed max we can report!"); +- *aUsage = INT64_MAX; +- } +- else { +- *aUsage += aDelta; +- } +-} +- + nsresult + IndexedDatabaseManager::AsyncUsageRunnable::TakeShortcut() + { +@@ -2295,25 +2280,22 @@ IndexedDatabaseManager::AsyncDeleteFileRunnable::Run() + nsCOMPtr<nsIFile> file = mFileManager->GetFileForId(directory, mFileId); + NS_ENSURE_TRUE(file, NS_ERROR_FAILURE); + +- nsString filePath; +- nsresult rv = file->GetPath(filePath); +- NS_ENSURE_SUCCESS(rv, rv); ++ nsresult rv; ++ int64_t fileSize; + +- int rc = sqlite3_quota_remove(NS_ConvertUTF16toUTF8(filePath).get()); +- if (rc != SQLITE_OK) { +- NS_WARNING("Failed to delete stored file!"); +- return NS_ERROR_FAILURE; ++ if (mFileManager->Privilege() != Chrome) { ++ rv = file->GetFileSize(&fileSize); ++ NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); + } + +- // sqlite3_quota_remove won't actually remove anything if we're not tracking +- // the quota here. Manually remove the file if it exists. +- bool exists; +- rv = file->Exists(&exists); +- NS_ENSURE_SUCCESS(rv, rv); ++ rv = file->Remove(false); ++ NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); + +- if (exists) { +- rv = file->Remove(false); +- NS_ENSURE_SUCCESS(rv, rv); ++ if (mFileManager->Privilege() != Chrome) { ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ quotaManager->DecreaseUsageForOrigin(mFileManager->Origin(), fileSize); + } + + directory = mFileManager->GetJournalDirectory(); +diff --git dom/indexedDB/IndexedDatabaseManager.h dom/indexedDB/IndexedDatabaseManager.h +index f9fbbf2..1ea5425 100644 +--- dom/indexedDB/IndexedDatabaseManager.h ++++ dom/indexedDB/IndexedDatabaseManager.h +@@ -23,7 +23,6 @@ + + #define INDEXEDDB_MANAGER_CONTRACTID "@mozilla.org/dom/indexeddb/manager;1" + +-class mozIStorageQuotaCallback; + class nsIAtom; + class nsIFile; + class nsITimer; +@@ -134,6 +133,8 @@ public: + FactoryPrivilege aPrivilege, + nsIFile** aDirectory); + ++ void UninitializeOriginsByPattern(const nsACString& aPattern); ++ + // Determine if the quota is lifted for the Window the current thread is + // using. + static inline bool +@@ -172,9 +173,7 @@ public: + const nsAString& aDatabaseName); + + void +- AddFileManager(const nsACString& aOrigin, +- const nsAString& aDatabaseName, +- FileManager* aFileManager); ++ AddFileManager(FileManager* aFileManager); + + void InvalidateFileManagersForPattern(const nsACString& aPattern); + +@@ -502,10 +501,6 @@ private: + // A timer that gets activated at shutdown to ensure we close all databases. + nsCOMPtr<nsITimer> mShutdownTimer; + +- // A single threadsafe instance of our quota callback. Created on the main +- // thread during GetOrCreate(). +- nsCOMPtr<mozIStorageQuotaCallback> mQuotaCallbackSingleton; +- + // A list of all successfully initialized origins. This list isn't protected + // by any mutex but it is only ever touched on the IO thread. + nsTArray<nsCString> mInitializedOrigins; +diff --git dom/indexedDB/Makefile.in dom/indexedDB/Makefile.in +index fef0858..09d4853 100644 +--- dom/indexedDB/Makefile.in ++++ dom/indexedDB/Makefile.in +@@ -25,7 +25,6 @@ CPPSRCS = \ + DatabaseInfo.cpp \ + FileInfo.cpp \ + FileManager.cpp \ +- FileStream.cpp \ + IDBCursor.cpp \ + IDBDatabase.cpp \ + IDBEvents.cpp \ +@@ -93,7 +92,6 @@ XPIDLSRCS = \ + nsIIDBVersionChangeEvent.idl \ + nsIIDBOpenDBRequest.idl \ + nsIIndexedDatabaseManager.idl \ +- nsIStandardFileStream.idl \ + $(NULL) + + DIRS += ipc +diff --git dom/indexedDB/OpenDatabaseHelper.cpp dom/indexedDB/OpenDatabaseHelper.cpp +index e71cad4..4cd7f61 100644 +--- dom/indexedDB/OpenDatabaseHelper.cpp ++++ dom/indexedDB/OpenDatabaseHelper.cpp +@@ -8,11 +8,12 @@ + + #include "nsIFile.h" + ++#include "mozilla/dom/quota/QuotaManager.h" + #include "mozilla/storage.h" + #include "nsEscape.h" ++#include "nsNetUtil.h" + #include "nsThreadUtils.h" + #include "snappy/snappy.h" +-#include "test_quota.h" + + #include "nsIBFCacheEntry.h" + #include "IDBEvents.h" +@@ -21,6 +22,7 @@ + + using namespace mozilla; + USING_INDEXEDDB_NAMESPACE ++USING_QUOTA_NAMESPACE + + namespace { + +@@ -1632,15 +1634,15 @@ OpenDatabaseHelper::DoDatabaseWork() + rv = dbFile->GetPath(mDatabaseFilePath); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- nsCOMPtr<nsIFile> fileManagerDirectory; +- rv = dbDirectory->Clone(getter_AddRefs(fileManagerDirectory)); ++ nsCOMPtr<nsIFile> fmDirectory; ++ rv = dbDirectory->Clone(getter_AddRefs(fmDirectory)); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- rv = fileManagerDirectory->Append(filename); ++ rv = fmDirectory->Append(filename); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + nsCOMPtr<mozIStorageConnection> connection; +- rv = CreateDatabaseConnection(mName, dbFile, fileManagerDirectory, ++ rv = CreateDatabaseConnection(dbFile, fmDirectory, mName, mASCIIOrigin, + getter_AddRefs(connection)); + if (NS_FAILED(rv) && + NS_ERROR_GET_MODULE(rv) != NS_ERROR_MODULE_DOM_INDEXEDDB) { +@@ -1691,12 +1693,12 @@ OpenDatabaseHelper::DoDatabaseWork() + + nsRefPtr<FileManager> fileManager = mgr->GetFileManager(mASCIIOrigin, mName); + if (!fileManager) { +- fileManager = new FileManager(mASCIIOrigin, mName); ++ fileManager = new FileManager(mASCIIOrigin, mPrivilege, mName); + +- rv = fileManager->Init(fileManagerDirectory, connection); ++ rv = fileManager->Init(fmDirectory, connection); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- mgr->AddFileManager(mASCIIOrigin, mName, fileManager); ++ mgr->AddFileManager(fileManager); + } + + mFileManager = fileManager.forget(); +@@ -1707,23 +1709,26 @@ OpenDatabaseHelper::DoDatabaseWork() + // static + nsresult + OpenDatabaseHelper::CreateDatabaseConnection( +- const nsAString& aName, + nsIFile* aDBFile, +- nsIFile* aFileManagerDirectory, ++ nsIFile* aFMDirectory, ++ const nsAString& aName, ++ const nsACString& aOrigin, + mozIStorageConnection** aConnection) + { + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); + +- NS_NAMED_LITERAL_CSTRING(quotaVFSName, "quota"); ++ nsCOMPtr<nsIFileURL> dbFileUrl = ++ IDBFactory::GetDatabaseFileURL(aDBFile, aOrigin); ++ NS_ENSURE_TRUE(dbFileUrl, NS_ERROR_FAILURE); + +- nsCOMPtr<mozIStorageServiceQuotaManagement> ss = ++ nsCOMPtr<mozIStorageService> ss = + do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID); + NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE); + + nsCOMPtr<mozIStorageConnection> connection; +- nsresult rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName, +- getter_AddRefs(connection)); ++ nsresult rv = ++ ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(connection)); + if (rv == NS_ERROR_FILE_CORRUPTED) { + // If we're just opening the database during origin initialization, then + // we don't want to erase any files. The failure here will fail origin +@@ -1737,21 +1742,20 @@ OpenDatabaseHelper::CreateDatabaseConnection( + NS_ENSURE_SUCCESS(rv, rv); + + bool exists; +- rv = aFileManagerDirectory->Exists(&exists); ++ rv = aFMDirectory->Exists(&exists); + NS_ENSURE_SUCCESS(rv, rv); + + if (exists) { + bool isDirectory; +- rv = aFileManagerDirectory->IsDirectory(&isDirectory); ++ rv = aFMDirectory->IsDirectory(&isDirectory); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- rv = aFileManagerDirectory->Remove(true); ++ rv = aFMDirectory->Remove(true); + NS_ENSURE_SUCCESS(rv, rv); + } + +- rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName, +- getter_AddRefs(connection)); ++ rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(connection)); + } + NS_ENSURE_SUCCESS(rv, rv); + +@@ -2347,6 +2351,8 @@ DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection) + { + NS_ASSERTION(!aConnection, "How did we get a connection here?"); + ++ const FactoryPrivilege& privilege = mOpenHelper->Privilege(); ++ + IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); + NS_ASSERTION(mgr, "This should never fail!"); + +@@ -2372,59 +2378,57 @@ DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection) + rv = dbFile->Exists(&exists); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- int rc; +- + if (exists) { +- nsString dbFilePath; +- rv = dbFile->GetPath(dbFilePath); +- NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); ++ int64_t fileSize; + +- rc = sqlite3_quota_remove(NS_ConvertUTF16toUTF8(dbFilePath).get()); +- if (rc != SQLITE_OK) { +- NS_WARNING("Failed to delete db file!"); +- return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; ++ if (privilege != Chrome) { ++ rv = dbFile->GetFileSize(&fileSize); ++ NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + } + +- // sqlite3_quota_remove won't actually remove anything if we're not tracking +- // the quota here. Manually remove the file if it exists. +- rv = dbFile->Exists(&exists); ++ rv = dbFile->Remove(false); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- if (exists) { +- rv = dbFile->Remove(false); +- NS_ENSURE_SUCCESS(rv, rv); ++ if (privilege != Chrome) { ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ quotaManager->DecreaseUsageForOrigin(mASCIIOrigin, fileSize); + } + } + +- nsCOMPtr<nsIFile> fileManagerDirectory; +- rv = directory->Clone(getter_AddRefs(fileManagerDirectory)); +- NS_ENSURE_SUCCESS(rv, rv); ++ nsCOMPtr<nsIFile> fmDirectory; ++ rv = directory->Clone(getter_AddRefs(fmDirectory)); ++ NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- rv = fileManagerDirectory->Append(filename); ++ rv = fmDirectory->Append(filename); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- rv = fileManagerDirectory->Exists(&exists); ++ rv = fmDirectory->Exists(&exists); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + if (exists) { + bool isDirectory; +- rv = fileManagerDirectory->IsDirectory(&isDirectory); ++ rv = fmDirectory->IsDirectory(&isDirectory); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- nsString fileManagerDirectoryPath; +- rv = fileManagerDirectory->GetPath(fileManagerDirectoryPath); +- NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); ++ uint64_t usage = 0; + +- rc = sqlite3_quota_remove( +- NS_ConvertUTF16toUTF8(fileManagerDirectoryPath).get()); +- if (rc != SQLITE_OK) { +- NS_WARNING("Failed to delete file directory!"); +- return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; ++ if (privilege != Chrome) { ++ rv = FileManager::GetUsage(fmDirectory, &usage); ++ NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + } + +- rv = fileManagerDirectory->Remove(true); +- NS_ENSURE_SUCCESS(rv, rv); ++ rv = fmDirectory->Remove(true); ++ NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); ++ ++ if (privilege != Chrome) { ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ quotaManager->DecreaseUsageForOrigin(mASCIIOrigin, usage); ++ } + } + + return NS_OK; +diff --git dom/indexedDB/OpenDatabaseHelper.h dom/indexedDB/OpenDatabaseHelper.h +index 587301b..5a3d987 100644 +--- dom/indexedDB/OpenDatabaseHelper.h ++++ dom/indexedDB/OpenDatabaseHelper.h +@@ -77,10 +77,16 @@ public: + return mDatabase; + } + ++ const FactoryPrivilege& Privilege() const ++ { ++ return mPrivilege; ++ } ++ + static +- nsresult CreateDatabaseConnection(const nsAString& aName, +- nsIFile* aDBFile, +- nsIFile* aFileManagerDirectory, ++ nsresult CreateDatabaseConnection(nsIFile* aDBFile, ++ nsIFile* aFMDirectory, ++ const nsAString& aName, ++ const nsACString& aOrigin, + mozIStorageConnection** aConnection); + + protected: +diff --git dom/indexedDB/nsIStandardFileStream.idl dom/indexedDB/nsIStandardFileStream.idl +deleted file mode 100644 +index 265c3ed..0000000 +--- dom/indexedDB/nsIStandardFileStream.idl ++++ /dev/null +@@ -1,60 +0,0 @@ +-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +-/* vim: set ts=2 et sw=2 tw=80: */ +-/* This Source Code Form is subject to the terms of the Mozilla Public +- * License, v. 2.0. If a copy of the MPL was not distributed with this file, +- * You can obtain one at http://mozilla.org/MPL/2.0/. */ +- +-#include "nsISupports.idl" +- +-interface nsIFile; +- +-/** +- * A stream that allows you to read from a file or stream to a file +- * using standard file APIs. +- */ +-[scriptable, uuid(ebbbb779-92a3-4b2a-b7cf-6efbe904c453)] +-interface nsIStandardFileStream : nsISupports +-{ +- /** +- * If this is set, the file will be opened (i.e., a call to +- * fopen done) only when we do an actual operation on the stream, +- * or more specifically, when one of the following is called: +- * - Seek +- * - Tell +- * - SetEOF +- * - Available +- * - Read +- * - Write +- * - Flush +- * - GetSize +- * - GetLastModified +- * - Sync +- * +- * FLAGS_DEFER_OPEN is useful if we use the stream on a background +- * thread, so that the opening and possible |stat|ing of the file +- * happens there as well. +- * +- * @note Using this flag results in the file not being opened +- * during the call to Init. This means that any errors that might +- * happen when this flag is not set would happen during the +- * first read. Also, the file is not locked when Init is called, +- * so it might be deleted before we try to read from it. +- */ +- const long FLAGS_DEFER_OPEN = 1 << 0; +- +- /** +- * @param file file to read from or stream to +- * @param mode file open mode (see fopen documentation) +- * @param flags flags specifying various behaviors of the class +- * (see enumerations in the class) +- */ +- void init(in nsIFile file, +- in AString mode, +- in long flags); +- +- /** +- * Flush all written content held in memory buffers out to disk. +- * This is the equivalent of fflush() +- */ +- void flushBuffers(); +-}; +diff --git dom/indexedDB/test/Makefile.in dom/indexedDB/test/Makefile.in +index 9c79b14..4c9a201 100644 +--- dom/indexedDB/test/Makefile.in ++++ dom/indexedDB/test/Makefile.in +@@ -54,11 +54,13 @@ MOCHITEST_FILES = \ + test_file_os_delete.html \ + test_file_put_get_object.html \ + test_file_put_get_values.html \ ++ test_file_quota.html \ + test_file_replace.html \ + test_file_resurrection_delete.html \ + test_file_resurrection_transaction_abort.html \ + test_file_sharing.html \ + test_file_transaction_abort.html \ ++ test_filehandle_quota.html \ + test_filehandle_serialization.html \ + test_filehandle_store_snapshot.html \ + test_getAll.html \ +diff --git dom/indexedDB/test/file.js dom/indexedDB/test/file.js +index 07bd10a..3c6194a 100644 +--- dom/indexedDB/test/file.js ++++ dom/indexedDB/test/file.js +@@ -3,6 +3,8 @@ + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + ++const DEFAULT_QUOTA = 50 * 1024 * 1024; ++ + var bufferCache = []; + var utils = SpecialPowers.getDOMWindowUtils(window); + +@@ -184,25 +186,6 @@ function getUsage(usageHandler) + idbManager.getUsageForURI(uri, callback); + } + +-function getUsageSync() +-{ +- let usage; +- +- getUsage(function(aUsage, aFileUsage) { +- usage = aUsage; +- }); +- +- let comp = SpecialPowers.wrap(Components); +- let thread = comp.classes["@mozilla.org/thread-manager;1"] +- .getService(comp.interfaces.nsIThreadManager) +- .currentThread; +- while (!usage) { +- thread.processNextEvent(true); +- } +- +- return usage; +-} +- + function scheduleGC() + { + SpecialPowers.exactGC(window, continueToNextStep); +diff --git dom/indexedDB/test/test_file_quota.html dom/indexedDB/test/test_file_quota.html +index b07880d..9fbc0c0 100644 +--- dom/indexedDB/test/test_file_quota.html ++++ dom/indexedDB/test/test_file_quota.html +@@ -13,14 +13,12 @@ + function testSteps() + { + const READ_WRITE = IDBTransaction.READ_WRITE; +- const DEFAULT_QUOTA_MB = 50; + + const name = window.location.pathname; + + const objectStoreName = "Blobs"; + +- const testData = { key: 0, value: {} }; +- const fileData = { key: 1, file: null }; ++ const fileData = { key: 1, file: getNullFile("random.bin", DEFAULT_QUOTA) }; + + let request = indexedDB.open(name, 1); + request.onerror = errorHandler; +@@ -32,21 +30,17 @@ + + let db = event.target.result; + +- let objectStore = db.createObjectStore(objectStoreName, { }); +- objectStore.add(testData.value, testData.key); +- +- let size = (DEFAULT_QUOTA_MB + 1) * 1024 * 1024 - getUsageSync(); +- fileData.file = getNullFile("random.bin", size); ++ db.createObjectStore(objectStoreName, { }); + + event = yield; + + is(event.type, "success", "Got correct event type"); + + trans = db.transaction([objectStoreName], READ_WRITE); +- objectStore = trans.objectStore(objectStoreName); ++ let objectStore = trans.objectStore(objectStoreName); + + request = objectStore.add(fileData.file, fileData.key); +- request.addEventListener("error", new ExpectError("UnknownError")); ++ request.addEventListener("error", new ExpectError("UnknownError", true)); + request.onsuccess = unexpectedSuccessHandler; + event = yield; + +diff --git dom/indexedDB/test/test_filehandle_quota.html dom/indexedDB/test/test_filehandle_quota.html +index addaf01..0506279 100644 +--- dom/indexedDB/test/test_filehandle_quota.html ++++ dom/indexedDB/test/test_filehandle_quota.html +@@ -13,7 +13,6 @@ + function testSteps() + { + const READ_WRITE = IDBTransaction.READ_WRITE; +- const DEFAULT_QUOTA_MB = 50; + + const name = window.location.pathname; + +@@ -39,10 +38,10 @@ + + let lockedFile = fileHandle.open("readwrite"); + +- let blob = getNullBlob((50 + 1) * 1024 * 1024 - getUsageSync()); ++ let blob = getNullBlob(DEFAULT_QUOTA); + + request = lockedFile.write(blob); +- request.addEventListener("error", new ExpectError("UnknownError")); ++ request.addEventListener("error", new ExpectError("UnknownError", true)); + request.onsuccess = unexpectedSuccessHandler; + event = yield; + +diff --git dom/quota/FileStreams.cpp dom/quota/FileStreams.cpp +new file mode 100644 +index 0000000..9de244f +--- /dev/null ++++ dom/quota/FileStreams.cpp +@@ -0,0 +1,123 @@ ++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* vim: set ts=2 et sw=2 tw=80: */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#include "FileStreams.h" ++ ++USING_QUOTA_NAMESPACE ++ ++template <class FileStreamBase> ++NS_IMETHODIMP ++FileQuotaStream<FileStreamBase>::SetEOF() ++{ ++ nsresult rv = FileStreamBase::SetEOF(); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ if (mQuotaObject) { ++ int64_t offset; ++ nsresult rv = FileStreamBase::Tell(&offset); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ mQuotaObject->UpdateSize(offset); ++ } ++ ++ return NS_OK; ++} ++ ++template <class FileStreamBase> ++NS_IMETHODIMP ++FileQuotaStream<FileStreamBase>::Close() ++{ ++ nsresult rv = FileStreamBase::Close(); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ mQuotaObject = nullptr; ++ ++ return NS_OK; ++} ++ ++template <class FileStreamBase> ++nsresult ++FileQuotaStream<FileStreamBase>::DoOpen() ++{ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ NS_ASSERTION(!mQuotaObject, "Creating quota object more than once?"); ++ mQuotaObject = quotaManager->GetQuotaObject(mOrigin, ++ FileStreamBase::mOpenParams.localFile); ++ ++ nsresult rv = FileStreamBase::DoOpen(); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ if (mQuotaObject && (FileStreamBase::mOpenParams.ioFlags & PR_TRUNCATE)) { ++ mQuotaObject->UpdateSize(0); ++ } ++ ++ return NS_OK; ++} ++ ++template <class FileStreamBase> ++NS_IMETHODIMP ++FileQuotaStreamWithWrite<FileStreamBase>::Write(const char* aBuf, ++ uint32_t aCount, ++ uint32_t* _retval) ++{ ++ nsresult rv; ++ ++ if (FileQuotaStreamWithWrite::mQuotaObject) { ++ int64_t offset; ++ rv = FileStreamBase::Tell(&offset); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ if (!FileQuotaStreamWithWrite:: ++ mQuotaObject->MaybeAllocateMoreSpace(offset, aCount)) { ++ return NS_ERROR_FAILURE; ++ } ++ } ++ ++ rv = FileStreamBase::Write(aBuf, aCount, _retval); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ return NS_OK; ++} ++ ++NS_IMPL_ISUPPORTS_INHERITED0(FileInputStream, nsFileInputStream) ++ ++already_AddRefed<FileInputStream> ++FileInputStream::Create(const nsACString& aOrigin, nsIFile* aFile, ++ int32_t aIOFlags, int32_t aPerm, ++ int32_t aBehaviorFlags) ++{ ++ nsRefPtr<FileInputStream> stream = new FileInputStream(aOrigin); ++ nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ return stream.forget(); ++} ++ ++NS_IMPL_ISUPPORTS_INHERITED0(FileOutputStream, nsFileOutputStream) ++ ++already_AddRefed<FileOutputStream> ++FileOutputStream::Create(const nsACString& aOrigin, nsIFile* aFile, ++ int32_t aIOFlags, int32_t aPerm, ++ int32_t aBehaviorFlags) ++{ ++ nsRefPtr<FileOutputStream> stream = new FileOutputStream(aOrigin); ++ nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ return stream.forget(); ++} ++ ++NS_IMPL_ISUPPORTS_INHERITED0(FileStream, nsFileStream) ++ ++already_AddRefed<FileStream> ++FileStream::Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags, ++ int32_t aPerm, int32_t aBehaviorFlags) ++{ ++ nsRefPtr<FileStream> stream = new FileStream(aOrigin); ++ nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ return stream.forget(); ++} +diff --git dom/quota/FileStreams.h dom/quota/FileStreams.h +new file mode 100644 +index 0000000..77bfad4 +--- /dev/null ++++ dom/quota/FileStreams.h +@@ -0,0 +1,115 @@ ++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* vim: set ts=2 et sw=2 tw=80: */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#ifndef mozilla_dom_quota_filestreams_h__ ++#define mozilla_dom_quota_filestreams_h__ ++ ++#include "QuotaCommon.h" ++ ++#include "nsFileStreams.h" ++ ++#include "QuotaManager.h" ++ ++BEGIN_QUOTA_NAMESPACE ++ ++template <class FileStreamBase> ++class FileQuotaStream : public FileStreamBase ++{ ++public: ++ // nsFileStreamBase override ++ NS_IMETHOD ++ SetEOF() MOZ_OVERRIDE; ++ ++ NS_IMETHOD ++ Close() MOZ_OVERRIDE; ++ ++protected: ++ FileQuotaStream(const nsACString& aOrigin) ++ : mOrigin(aOrigin) ++ { } ++ ++ // nsFileStreamBase override ++ virtual nsresult ++ DoOpen() MOZ_OVERRIDE; ++ ++ nsCString mOrigin; ++ nsRefPtr<QuotaObject> mQuotaObject; ++}; ++ ++template <class FileStreamBase> ++class FileQuotaStreamWithWrite : public FileQuotaStream<FileStreamBase> ++{ ++public: ++ // nsFileStreamBase override ++ NS_IMETHOD ++ Write(const char* aBuf, uint32_t aCount, uint32_t* _retval) MOZ_OVERRIDE; ++ ++protected: ++ FileQuotaStreamWithWrite(const nsACString& aOrigin) ++ : FileQuotaStream<FileStreamBase>(aOrigin) ++ { } ++}; ++ ++class FileInputStream : public FileQuotaStream<nsFileInputStream> ++{ ++public: ++ NS_DECL_ISUPPORTS_INHERITED ++ ++ static already_AddRefed<FileInputStream> ++ Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1, ++ int32_t aPerm = -1, int32_t aBehaviorFlags = 0); ++ ++private: ++ FileInputStream(const nsACString& aOrigin) ++ : FileQuotaStream<nsFileInputStream>(aOrigin) ++ { } ++ ++ virtual ~FileInputStream() { ++ Close(); ++ } ++}; ++ ++class FileOutputStream : public FileQuotaStreamWithWrite<nsFileOutputStream> ++{ ++public: ++ NS_DECL_ISUPPORTS_INHERITED ++ ++ static already_AddRefed<FileOutputStream> ++ Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1, ++ int32_t aPerm = -1, int32_t aBehaviorFlags = 0); ++ ++private: ++ FileOutputStream(const nsACString& aOrigin) ++ : FileQuotaStreamWithWrite<nsFileOutputStream>(aOrigin) ++ { } ++ ++ virtual ~FileOutputStream() { ++ Close(); ++ } ++}; ++ ++class FileStream : public FileQuotaStreamWithWrite<nsFileStream> ++{ ++public: ++ NS_DECL_ISUPPORTS_INHERITED ++ ++ static already_AddRefed<FileStream> ++ Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1, ++ int32_t aPerm = -1, int32_t aBehaviorFlags = 0); ++ ++private: ++ FileStream(const nsACString& aOrigin) ++ : FileQuotaStreamWithWrite<nsFileStream>(aOrigin) ++ { } ++ ++ virtual ~FileStream() { ++ Close(); ++ } ++}; ++ ++END_QUOTA_NAMESPACE ++ ++#endif /* mozilla_dom_quota_filestreams_h__ */ +diff --git dom/quota/Makefile.in dom/quota/Makefile.in +new file mode 100644 +index 0000000..49be551 +--- /dev/null ++++ dom/quota/Makefile.in +@@ -0,0 +1,33 @@ ++# This Source Code Form is subject to the terms of the Mozilla Public ++# License, v. 2.0. If a copy of the MPL was not distributed with this file, ++# You can obtain one at http://mozilla.org/MPL/2.0/. ++ ++DEPTH = ../.. ++topsrcdir = @top_srcdir@ ++srcdir = @srcdir@ ++VPATH = @srcdir@ ++ ++include $(DEPTH)/config/autoconf.mk ++ ++MODULE = dom ++LIBRARY_NAME = domquota_s ++XPIDL_MODULE = dom_quota ++LIBXUL_LIBRARY = 1 ++FORCE_STATIC_LIB = 1 ++ ++include $(topsrcdir)/dom/dom-config.mk ++ ++EXPORTS_NAMESPACES = mozilla/dom/quota ++ ++CPPSRCS = \ ++ FileStreams.cpp \ ++ QuotaManager.cpp \ ++ $(NULL) ++ ++EXPORTS_mozilla/dom/quota = \ ++ FileStreams.h \ ++ QuotaCommon.h \ ++ QuotaManager.h \ ++ $(NULL) ++ ++include $(topsrcdir)/config/rules.mk +diff --git dom/quota/QuotaCommon.h dom/quota/QuotaCommon.h +new file mode 100644 +index 0000000..a415d17 +--- /dev/null ++++ dom/quota/QuotaCommon.h +@@ -0,0 +1,23 @@ ++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* vim: set ts=2 et sw=2 tw=80: */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this file, ++ * You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#ifndef mozilla_dom_quota_quotacommon_h__ ++#define mozilla_dom_quota_quotacommon_h__ ++ ++#include "nsAutoPtr.h" ++#include "nsCOMPtr.h" ++#include "nsDebug.h" ++#include "nsStringGlue.h" ++#include "nsTArray.h" ++ ++#define BEGIN_QUOTA_NAMESPACE \ ++ namespace mozilla { namespace dom { namespace quota { ++#define END_QUOTA_NAMESPACE \ ++ } /* namespace quota */ } /* namespace dom */ } /* namespace mozilla */ ++#define USING_QUOTA_NAMESPACE \ ++ using namespace mozilla::dom::quota; ++ ++#endif // mozilla_dom_quota_quotacommon_h__ +diff --git dom/quota/QuotaManager.cpp dom/quota/QuotaManager.cpp +new file mode 100644 +index 0000000..b251606 +--- /dev/null ++++ dom/quota/QuotaManager.cpp +@@ -0,0 +1,294 @@ ++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* vim: set ts=2 et sw=2 tw=80: */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this file, ++ * You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#include "QuotaManager.h" ++ ++#include "nsIFile.h" ++ ++#include "mozilla/ClearOnShutdown.h" ++#include "nsComponentManagerUtils.h" ++ ++#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h" ++ ++USING_QUOTA_NAMESPACE ++ ++namespace { ++ ++nsAutoPtr<QuotaManager> gInstance; ++ ++PLDHashOperator ++RemoveQuotaForPatternCallback(const nsACString& aKey, ++ nsRefPtr<OriginInfo>& aValue, ++ void* aUserArg) ++{ ++ NS_ASSERTION(!aKey.IsEmpty(), "Empty key!"); ++ NS_ASSERTION(aValue, "Null pointer!"); ++ NS_ASSERTION(aUserArg, "Null pointer!"); ++ ++ const nsACString* pattern = ++ static_cast<const nsACString*>(aUserArg); ++ ++ if (StringBeginsWith(aKey, *pattern)) { ++ return PL_DHASH_REMOVE; ++ } ++ ++ return PL_DHASH_NEXT; ++} ++ ++} // anonymous namespace ++ ++void ++QuotaObject::AddRef() ++{ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ if (!quotaManager) { ++ NS_ERROR("Null quota manager, this shouldn't happen, possible leak!"); ++ ++ NS_AtomicIncrementRefcnt(mRefCnt); ++ ++ return; ++ } ++ ++ MutexAutoLock lock(quotaManager->mQuotaMutex); ++ ++ ++mRefCnt; ++} ++ ++void ++QuotaObject::Release() ++{ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ if (!quotaManager) { ++ NS_ERROR("Null quota manager, this shouldn't happen, possible leak!"); ++ ++ nsrefcnt count = NS_AtomicDecrementRefcnt(mRefCnt); ++ if (count == 0) { ++ mRefCnt = 1; ++ delete this; ++ } ++ ++ return; ++ } ++ ++ { ++ MutexAutoLock lock(quotaManager->mQuotaMutex); ++ ++ --mRefCnt; ++ ++ if (mRefCnt > 0) { ++ return; ++ } ++ ++ if (mOriginInfo) { ++ mOriginInfo->mQuotaObjects.Remove(mPath); ++ } ++ } ++ ++ delete this; ++} ++ ++void ++QuotaObject::UpdateSize(int64_t aSize) ++{ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ MutexAutoLock lock(quotaManager->mQuotaMutex); ++ ++ if (mOriginInfo) { ++ mOriginInfo->mUsage -= mSize; ++ mSize = aSize; ++ mOriginInfo->mUsage += mSize; ++ } ++} ++ ++bool ++QuotaObject::MaybeAllocateMoreSpace(int64_t aOffset, int32_t aCount) ++{ ++ int64_t end = aOffset + aCount; ++ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ MutexAutoLock lock(quotaManager->mQuotaMutex); ++ ++ if (mSize >= end || !mOriginInfo) { ++ return true; ++ } ++ ++ int64_t newUsage = mOriginInfo->mUsage - mSize + end; ++ if (newUsage > mOriginInfo->mLimit) { ++ if (!indexedDB::IndexedDatabaseManager::QuotaIsLifted()) { ++ return false; ++ } ++ ++ nsCString origin = mOriginInfo->mOrigin; ++ ++ mOriginInfo->LockedClearOriginInfos(); ++ NS_ASSERTION(!mOriginInfo, ++ "Should have cleared in LockedClearOriginInfos!"); ++ ++ quotaManager->mOriginInfos.Remove(origin); ++ ++ mSize = end; ++ ++ return true; ++ } ++ ++ mOriginInfo->mUsage = newUsage; ++ mSize = end; ++ ++ return true; ++} ++ ++#ifdef DEBUG ++void ++OriginInfo::LockedClearOriginInfos() ++{ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ quotaManager->mQuotaMutex.AssertCurrentThreadOwns(); ++ ++ mQuotaObjects.EnumerateRead(ClearOriginInfoCallback, nullptr); ++} ++#endif ++ ++// static ++PLDHashOperator ++OriginInfo::ClearOriginInfoCallback(const nsAString& aKey, ++ QuotaObject* aValue, ++ void* aUserArg) ++{ ++ NS_ASSERTION(!aKey.IsEmpty(), "Empty key!"); ++ NS_ASSERTION(aValue, "Null pointer!"); ++ ++ aValue->mOriginInfo = nullptr; ++ ++ return PL_DHASH_NEXT; ++} ++ ++// static ++QuotaManager* ++QuotaManager::GetOrCreate() ++{ ++ if (!gInstance) { ++ NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); ++ ++ gInstance = new QuotaManager(); ++ ++ ClearOnShutdown(&gInstance); ++ } ++ ++ return gInstance; ++} ++ ++// static ++QuotaManager* ++QuotaManager::Get() ++{ ++ // Does not return an owning reference. ++ return gInstance; ++} ++ ++void ++QuotaManager::InitQuotaForOrigin(const nsACString& aOrigin, ++ int64_t aLimit, ++ int64_t aUsage) ++{ ++ OriginInfo* info = new OriginInfo(aOrigin, aLimit * 1024 * 1024, aUsage); ++ ++ MutexAutoLock lock(mQuotaMutex); ++ ++ NS_ASSERTION(!mOriginInfos.GetWeak(aOrigin), "Replacing an existing entry!"); ++ mOriginInfos.Put(aOrigin, info); ++} ++ ++void ++QuotaManager::DecreaseUsageForOrigin(const nsACString& aOrigin, ++ int64_t aSize) ++{ ++ MutexAutoLock lock(mQuotaMutex); ++ ++ nsRefPtr<OriginInfo> originInfo; ++ mOriginInfos.Get(aOrigin, getter_AddRefs(originInfo)); ++ ++ if (originInfo) { ++ originInfo->mUsage -= aSize; ++ } ++} ++ ++void ++QuotaManager::RemoveQuotaForPattern(const nsACString& aPattern) ++{ ++ NS_ASSERTION(!aPattern.IsEmpty(), "Empty pattern!"); ++ ++ MutexAutoLock lock(mQuotaMutex); ++ ++ mOriginInfos.Enumerate(RemoveQuotaForPatternCallback, ++ const_cast<nsACString*>(&aPattern)); ++} ++ ++already_AddRefed<QuotaObject> ++QuotaManager::GetQuotaObject(const nsACString& aOrigin, ++ nsIFile* aFile) ++{ ++ NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); ++ ++ nsString path; ++ nsresult rv = aFile->GetPath(path); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ ++ int64_t fileSize; ++ ++ bool exists; ++ rv = aFile->Exists(&exists); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ ++ if (exists) { ++ rv = aFile->GetFileSize(&fileSize); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ } ++ else { ++ fileSize = 0; ++ } ++ ++ QuotaObject* info = nullptr; ++ { ++ MutexAutoLock lock(mQuotaMutex); ++ ++ nsRefPtr<OriginInfo> originInfo; ++ mOriginInfos.Get(aOrigin, getter_AddRefs(originInfo)); ++ ++ if (!originInfo) { ++ return nullptr; ++ } ++ ++ originInfo->mQuotaObjects.Get(path, &info); ++ ++ if (!info) { ++ info = new QuotaObject(originInfo, path, fileSize); ++ originInfo->mQuotaObjects.Put(path, info); ++ } ++ } ++ ++ nsRefPtr<QuotaObject> result = info; ++ return result.forget(); ++} ++ ++already_AddRefed<QuotaObject> ++QuotaManager::GetQuotaObject(const nsACString& aOrigin, ++ const nsAString& aPath) ++{ ++ nsresult rv; ++ nsCOMPtr<nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ ++ rv = file->InitWithPath(aPath); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ ++ return GetQuotaObject(aOrigin, file); ++} +diff --git dom/quota/QuotaManager.h dom/quota/QuotaManager.h +new file mode 100644 +index 0000000..e19acdd +--- /dev/null ++++ dom/quota/QuotaManager.h +@@ -0,0 +1,147 @@ ++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* vim: set ts=2 et sw=2 tw=80: */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this file, ++ * You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#ifndef mozilla_dom_quota_quotamanager_h__ ++#define mozilla_dom_quota_quotamanager_h__ ++ ++#include "QuotaCommon.h" ++ ++#include "mozilla/Mutex.h" ++#include "nsDataHashtable.h" ++#include "nsRefPtrHashtable.h" ++#include "nsThreadUtils.h" ++ ++BEGIN_QUOTA_NAMESPACE ++ ++class OriginInfo; ++class QuotaManager; ++ ++class QuotaObject ++{ ++ friend class OriginInfo; ++ friend class QuotaManager; ++ ++public: ++ void ++ AddRef(); ++ ++ void ++ Release(); ++ ++ void ++ UpdateSize(int64_t aSize); ++ ++ bool ++ MaybeAllocateMoreSpace(int64_t aOffset, int32_t aCount); ++ ++private: ++ QuotaObject(OriginInfo* aOriginInfo, const nsAString& aPath, int64_t aSize) ++ : mOriginInfo(aOriginInfo), mPath(aPath), mSize(aSize) ++ { } ++ ++ virtual ~QuotaObject() ++ { } ++ ++ nsAutoRefCnt mRefCnt; ++ ++ OriginInfo* mOriginInfo; ++ nsString mPath; ++ int64_t mSize; ++}; ++ ++class OriginInfo ++{ ++ friend class QuotaManager; ++ friend class QuotaObject; ++ ++public: ++ OriginInfo(const nsACString& aOrigin, int64_t aLimit, int64_t aUsage) ++ : mOrigin(aOrigin), mLimit(aLimit), mUsage(aUsage) ++ { ++ mQuotaObjects.Init(); ++ } ++ ++ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OriginInfo) ++ ++private: ++ void ++#ifdef DEBUG ++ LockedClearOriginInfos(); ++#else ++ LockedClearOriginInfos() ++ { ++ mQuotaObjects.EnumerateRead(ClearOriginInfoCallback, nullptr); ++ } ++#endif ++ ++ static PLDHashOperator ++ ClearOriginInfoCallback(const nsAString& aKey, ++ QuotaObject* aValue, void* aUserArg); ++ ++ nsDataHashtable<nsStringHashKey, QuotaObject*> mQuotaObjects; ++ ++ nsCString mOrigin; ++ int64_t mLimit; ++ int64_t mUsage; ++}; ++ ++class QuotaManager ++{ ++ friend class nsAutoPtr<QuotaManager>; ++ friend class OriginInfo; ++ friend class QuotaObject; ++ ++public: ++ // Returns a non-owning reference. ++ static QuotaManager* ++ GetOrCreate(); ++ ++ // Returns a non-owning reference. ++ static QuotaManager* ++ Get(); ++ ++ void ++ InitQuotaForOrigin(const nsACString& aOrigin, ++ int64_t aLimit, ++ int64_t aUsage); ++ ++ void ++ DecreaseUsageForOrigin(const nsACString& aOrigin, ++ int64_t aSize); ++ ++ void ++ RemoveQuotaForPattern(const nsACString& aPattern); ++ ++ already_AddRefed<QuotaObject> ++ GetQuotaObject(const nsACString& aOrigin, ++ nsIFile* aFile); ++ ++ already_AddRefed<QuotaObject> ++ GetQuotaObject(const nsACString& aOrigin, ++ const nsAString& aPath); ++ ++private: ++ QuotaManager() ++ : mQuotaMutex("QuotaManager.mQuotaMutex") ++ { ++ NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); ++ ++ mOriginInfos.Init(); ++ } ++ ++ virtual ~QuotaManager() ++ { ++ NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); ++ } ++ ++ mozilla::Mutex mQuotaMutex; ++ ++ nsRefPtrHashtable<nsCStringHashKey, OriginInfo> mOriginInfos; ++}; ++ ++END_QUOTA_NAMESPACE ++ ++#endif /* mozilla_dom_quota_quotamanager_h__ */ +diff --git layout/build/Makefile.in layout/build/Makefile.in +index e6b32da..496b55f 100644 +--- layout/build/Makefile.in ++++ layout/build/Makefile.in +@@ -69,6 +69,7 @@ SHARED_LIBRARY_LIBS = \ + $(DEPTH)/dom/encoding/$(LIB_PREFIX)domencoding_s.$(LIB_SUFFIX) \ + $(DEPTH)/dom/file/$(LIB_PREFIX)domfile_s.$(LIB_SUFFIX) \ + $(DEPTH)/dom/power/$(LIB_PREFIX)dom_power_s.$(LIB_SUFFIX) \ ++ $(DEPTH)/dom/quota/$(LIB_PREFIX)domquota_s.$(LIB_SUFFIX) \ + $(DEPTH)/dom/settings/$(LIB_PREFIX)jsdomsettings_s.$(LIB_SUFFIX) \ + $(DEPTH)/dom/permission/$(LIB_PREFIX)jsdompermissionsettings_s.$(LIB_SUFFIX) \ + $(DEPTH)/dom/network/src/$(LIB_PREFIX)dom_network_s.$(LIB_SUFFIX) \ +diff --git netwerk/base/src/Makefile.in netwerk/base/src/Makefile.in +index 0c0d60e..e8cef48 100644 +--- netwerk/base/src/Makefile.in ++++ netwerk/base/src/Makefile.in +@@ -19,6 +19,7 @@ LIBXUL_LIBRARY = 1 + EXPORTS = \ + nsMIMEInputStream.h \ + nsURLHelper.h \ ++ nsFileStreams.h \ + $(NULL) + + EXPORTS_NAMESPACES = mozilla/net +diff --git netwerk/base/src/nsFileStreams.cpp netwerk/base/src/nsFileStreams.cpp +index 2420ffc..ecc26aa 100644 +--- netwerk/base/src/nsFileStreams.cpp ++++ netwerk/base/src/nsFileStreams.cpp +@@ -51,7 +51,9 @@ nsFileStreamBase::~nsFileStreamBase() + Close(); + } + +-NS_IMPL_THREADSAFE_ISUPPORTS1(nsFileStreamBase, nsISeekableStream) ++NS_IMPL_THREADSAFE_ISUPPORTS2(nsFileStreamBase, ++ nsISeekableStream, ++ nsIFileMetadata) + + NS_IMETHODIMP + nsFileStreamBase::Seek(int32_t whence, int64_t offset) +@@ -124,6 +126,52 @@ nsFileStreamBase::SetEOF() + return NS_OK; + } + ++NS_IMETHODIMP ++nsFileStreamBase::GetSize(int64_t* _retval) ++{ ++ nsresult rv = DoPendingOpen(); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ if (!mFD) { ++ return NS_BASE_STREAM_CLOSED; ++ } ++ ++ PRFileInfo64 info; ++ if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) { ++ return NS_BASE_STREAM_OSERROR; ++ } ++ ++ *_retval = int64_t(info.size); ++ ++ return NS_OK; ++} ++ ++NS_IMETHODIMP ++nsFileStreamBase::GetLastModified(int64_t* _retval) ++{ ++ nsresult rv = DoPendingOpen(); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ if (!mFD) { ++ return NS_BASE_STREAM_CLOSED; ++ } ++ ++ PRFileInfo64 info; ++ if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) { ++ return NS_BASE_STREAM_OSERROR; ++ } ++ ++ int64_t modTime = int64_t(info.modifyTime); ++ if (modTime == 0) { ++ *_retval = 0; ++ } ++ else { ++ *_retval = modTime / int64_t(PR_USEC_PER_MSEC); ++ } ++ ++ return NS_OK; ++} ++ + nsresult + nsFileStreamBase::Close() + { +@@ -934,13 +982,12 @@ nsSafeFileOutputStream::Write(const char *buf, uint32_t count, uint32_t *result) + //////////////////////////////////////////////////////////////////////////////// + // nsFileStream + +-NS_IMPL_ISUPPORTS_INHERITED4(nsFileStream, ++NS_IMPL_ISUPPORTS_INHERITED3(nsFileStream, + nsFileStreamBase, + nsIInputStream, + nsIOutputStream, +- nsIFileStream, +- nsIFileMetadata) +- ++ nsIFileStream) ++ + NS_IMETHODIMP + nsFileStream::Init(nsIFile* file, int32_t ioFlags, int32_t perm, + int32_t behaviorFlags) +@@ -959,50 +1006,4 @@ nsFileStream::Init(nsIFile* file, int32_t ioFlags, int32_t perm, + mBehaviorFlags & nsIFileStream::DEFER_OPEN); + } + +-NS_IMETHODIMP +-nsFileStream::GetSize(int64_t* _retval) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mFD) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- PRFileInfo64 info; +- if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) { +- return NS_BASE_STREAM_OSERROR; +- } +- +- *_retval = int64_t(info.size); +- +- return NS_OK; +-} +- +-NS_IMETHODIMP +-nsFileStream::GetLastModified(int64_t* _retval) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mFD) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- PRFileInfo64 info; +- if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) { +- return NS_BASE_STREAM_OSERROR; +- } +- +- int64_t modTime = int64_t(info.modifyTime); +- if (modTime == 0) { +- *_retval = 0; +- } +- else { +- *_retval = modTime / int64_t(PR_USEC_PER_MSEC); +- } +- +- return NS_OK; +-} +- + //////////////////////////////////////////////////////////////////////////////// +diff --git netwerk/base/src/nsFileStreams.h netwerk/base/src/nsFileStreams.h +index 13e5b45..1aa6a82 100644 +--- netwerk/base/src/nsFileStreams.h ++++ netwerk/base/src/nsFileStreams.h +@@ -24,11 +24,13 @@ + + //////////////////////////////////////////////////////////////////////////////// + +-class nsFileStreamBase : public nsISeekableStream ++class nsFileStreamBase : public nsISeekableStream, ++ public nsIFileMetadata + { + public: + NS_DECL_ISUPPORTS + NS_DECL_NSISEEKABLESTREAM ++ NS_DECL_NSIFILEMETADATA + + nsFileStreamBase(); + virtual ~nsFileStreamBase(); +@@ -124,8 +126,8 @@ public: + NS_IMETHOD IsNonBlocking(bool* _retval) + { + return nsFileStreamBase::IsNonBlocking(_retval); +- } +- ++ } ++ + // Overrided from nsFileStreamBase + NS_IMETHOD Seek(int32_t aWhence, int64_t aOffset); + +@@ -260,13 +262,11 @@ protected: + class nsFileStream : public nsFileStreamBase, + public nsIInputStream, + public nsIOutputStream, +- public nsIFileStream, +- public nsIFileMetadata ++ public nsIFileStream + { + public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIFILESTREAM +- NS_DECL_NSIFILEMETADATA + NS_FORWARD_NSIINPUTSTREAM(nsFileStreamBase::) + + // Can't use NS_FORWARD_NSIOUTPUTSTREAM due to overlapping methods +diff --git storage/public/Makefile.in storage/public/Makefile.in +index c485d4e..c05e6f3 100644 +--- storage/public/Makefile.in ++++ storage/public/Makefile.in +@@ -36,7 +36,6 @@ XPIDLSRCS = \ + mozIStorageCompletionCallback.idl \ + mozIStorageBaseStatement.idl \ + mozIStorageAsyncStatement.idl \ +- mozIStorageServiceQuotaManagement.idl \ + mozIStorageVacuumParticipant.idl \ + $(NULL) + # SEE ABOVE NOTE! +diff --git storage/public/mozIStorageService.idl storage/public/mozIStorageService.idl +index 3087a11..483649b 100644 +--- storage/public/mozIStorageService.idl ++++ storage/public/mozIStorageService.idl +@@ -7,6 +7,7 @@ + + interface mozIStorageConnection; + interface nsIFile; ++interface nsIFileURL; + + /** + * The mozIStorageService interface is intended to be implemented by +@@ -15,7 +16,7 @@ interface nsIFile; + * + * This is the only way to open a database connection. + */ +-[scriptable, uuid(fe8e95cb-b377-4c8d-bccb-d9198c67542b)] ++[scriptable, uuid(12bfad34-cca3-40fb-8736-d8bf9db61a27)] + interface mozIStorageService : nsISupports { + /** + * Get a connection to a named special database storage. +@@ -106,6 +107,16 @@ interface mozIStorageService : nsISupports { + */ + mozIStorageConnection openUnsharedDatabase(in nsIFile aDatabaseFile); + ++ /** ++ * See openDatabase(). Exactly the same only initialized with a file URL. ++ * Custom parameters can be passed to SQLite and VFS implementations through ++ * the query part of the URL. ++ * ++ * @param aURL ++ * A nsIFileURL that represents the database that is to be opened. ++ */ ++ mozIStorageConnection openDatabaseWithFileURL(in nsIFileURL aFileURL); ++ + /* + * Utilities + */ +diff --git storage/public/mozIStorageServiceQuotaManagement.idl storage/public/mozIStorageServiceQuotaManagement.idl +deleted file mode 100644 +index ee5086b..0000000 +--- storage/public/mozIStorageServiceQuotaManagement.idl ++++ /dev/null +@@ -1,99 +0,0 @@ +-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +-/* vim: set ts=2 et sw=2 tw=80: */ +-/* This Source Code Form is subject to the terms of the Mozilla Public +- * License, v. 2.0. If a copy of the MPL was not distributed with this +- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +- +-#include "nsISupports.idl" +- +-interface mozIStorageConnection; +-interface nsIFile; +- +-[scriptable, function, uuid(ae94f0a5-ebdf-48f4-9959-085e13235d8d)] +-interface mozIStorageQuotaCallback : nsISupports +-{ +- /** +- * Called when the file size quota for a group of databases is exceeded. +- * +- * @param aFilename +- * The filename of the database that has exceeded the quota. +- * +- * @param aCurrentSizeLimit +- * The current size (in bytes) of the quota. +- * +- * @param aCurrentTotalSize +- * The current size of all databases in the quota group. +- * +- * @param aUserData +- * Any additional data that was provided to the +- * setQuotaForFilenamePattern function. +- * +- * @returns A new quota size. A new quota of 0 will disable the quota callback +- * and any quota value less than aCurrentTotalSize will cause the +- * database operation to fail with NS_ERROR_FILE_NO_DEVICE_SPACE. +- */ +- long long quotaExceeded(in ACString aFilename, +- in long long aCurrentSizeLimit, +- in long long aCurrentTotalSize, +- in nsISupports aUserData); +-}; +- +-/** +- * This is a temporary interface that should eventually merge with +- * mozIStorageService. +- */ +-[scriptable, uuid(4d81faf5-fe01-428b-99b8-c94cba12fd72)] +-interface mozIStorageServiceQuotaManagement : nsISupports +-{ +- /** +- * See mozIStorageService.openDatabase. Exactly the same only with a custom +- * SQLite VFS. +- */ +- mozIStorageConnection openDatabaseWithVFS(in nsIFile aDatabaseFile, +- in ACString aVFSName); +- +- /** +- * Set a file size quota for a group of databases matching the given filename +- * pattern, optionally specifying a callback when the quota is exceeded. +- * +- * @param aPattern +- * A pattern to match filenames for inclusion in the quota system. May +- * contain the following special characters: +- * '*' Matches any sequence of zero or more characters. +- * '?' Matches exactly one character. +- * [...] Matches one character from the enclosed list of characters. +- * [^...] Matches one character not in the enclosed list. +- * +- * @param aSizeLimit +- * The size limit (in bytes) for the quota group. +- * +- * @param aCallback +- * A callback that will be used when the quota is exceeded. +- * +- * @param aUserData +- * Additional information to be passed to the callback. +- */ +- void setQuotaForFilenamePattern(in ACString aPattern, +- in long long aSizeLimit, +- in mozIStorageQuotaCallback aCallback, +- in nsISupports aUserData); +- +- /** +- * Adds, removes, or updates the file size information maintained by the quota +- * system for files not opened through openDatabaseWithVFS(). +- * +- * Use this function when you want files to be included in quota calculations +- * that are either a) not SQLite databases, or b) SQLite databases that have +- * not been opened. +- * +- * This function will have no effect on files that do not match an existing +- * quota pattern (set previously by setQuotaForFilenamePattern()). +- * +- * @param aFile +- * The file for which quota information should be updated. If the file +- * exists then its size information will be added or refreshed. If the +- * file does not exist then the file will be removed from tracking +- * under the quota system. +- */ +- void updateQuotaInformationForFile(in nsIFile aFile); +-}; +diff --git storage/public/storage.h storage/public/storage.h +index 8e571e2..08f39f3 100644 +--- storage/public/storage.h ++++ storage/public/storage.h +@@ -24,7 +24,6 @@ + #include "mozIStorageStatementCallback.h" + #include "mozIStorageBindingParamsArray.h" + #include "mozIStorageBindingParams.h" +-#include "mozIStorageServiceQuotaManagement.h" + #include "mozIStorageVacuumParticipant.h" + #include "mozIStorageCompletionCallback.h" + #include "mozIStorageAsyncStatement.h" +diff --git storage/src/TelemetryVFS.cpp storage/src/TelemetryVFS.cpp +index 60de5c4..e4fce09 100644 +--- storage/src/TelemetryVFS.cpp ++++ storage/src/TelemetryVFS.cpp +@@ -10,6 +10,7 @@ + #include "sqlite3.h" + #include "nsThreadUtils.h" + #include "mozilla/Util.h" ++#include "mozilla/dom/quota/QuotaManager.h" + + /** + * This preference is a workaround to allow users/sysadmins to identify +@@ -24,6 +25,7 @@ + namespace { + + using namespace mozilla; ++using namespace mozilla::dom::quota; + + struct Histograms { + const char *name; +@@ -82,9 +84,17 @@ private: + }; + + struct telemetry_file { +- sqlite3_file base; // Base class. Must be first +- Histograms *histograms; // histograms pertaining to this file +- sqlite3_file pReal[1]; // This contains the vfs that actually does work ++ // Base class. Must be first ++ sqlite3_file base; ++ ++ // histograms pertaining to this file ++ Histograms *histograms; ++ ++ // quota object for this file ++ nsRefPtr<QuotaObject> quotaObject; ++ ++ // This contains the vfs that actually does work ++ sqlite3_file pReal[1]; + }; + + /* +@@ -99,6 +109,7 @@ xClose(sqlite3_file *pFile) + if( rc==SQLITE_OK ){ + delete p->base.pMethods; + p->base.pMethods = NULL; ++ p->quotaObject = nullptr; + } + return rc; + } +@@ -126,6 +137,9 @@ int + xWrite(sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite_int64 iOfst) + { + telemetry_file *p = (telemetry_file *)pFile; ++ if (p->quotaObject && !p->quotaObject->MaybeAllocateMoreSpace(iOfst, iAmt)) { ++ return SQLITE_FULL; ++ } + IOThreadAutoTimer ioTimer(p->histograms->writeMS); + int rc; + rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst); +@@ -144,6 +158,9 @@ xTruncate(sqlite3_file *pFile, sqlite_int64 size) + int rc; + Telemetry::AutoTimer<Telemetry::MOZ_SQLITE_TRUNCATE_MS> timer; + rc = p->pReal->pMethods->xTruncate(p->pReal, size); ++ if (rc == SQLITE_OK && p->quotaObject) { ++ p->quotaObject->UpdateSize(size); ++ } + return rc; + } + +@@ -300,6 +317,18 @@ xOpen(sqlite3_vfs* vfs, const char *zName, sqlite3_file* pFile, + break; + } + p->histograms = h; ++ ++ const char* origin; ++ if ((flags & SQLITE_OPEN_URI) && ++ (origin = sqlite3_uri_parameter(zName, "origin"))) { ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ MOZ_ASSERT(quotaManager); ++ ++ p->quotaObject = quotaManager->GetQuotaObject(nsDependentCString(origin), ++ NS_ConvertUTF8toUTF16(zName)); ++ ++ } ++ + rc = orig_vfs->xOpen(orig_vfs, zName, p->pReal, flags, pOutFlags); + if( rc != SQLITE_OK ) + return rc; +diff --git storage/src/mozStorageConnection.cpp storage/src/mozStorageConnection.cpp +index 3afd3e1b..430824a 100644 +--- storage/src/mozStorageConnection.cpp ++++ storage/src/mozStorageConnection.cpp +@@ -12,6 +12,7 @@ + #include "nsIMemoryReporter.h" + #include "nsThreadUtils.h" + #include "nsIFile.h" ++#include "nsIFileURL.h" + #include "mozilla/Telemetry.h" + #include "mozilla/Mutex.h" + #include "mozilla/CondVar.h" +@@ -471,34 +472,83 @@ Connection::getAsyncExecutionTarget() + } + + nsresult +-Connection::initialize(nsIFile *aDatabaseFile, +- const char* aVFSName) ++Connection::initialize() + { + NS_ASSERTION (!mDBConn, "Initialize called on already opened database!"); + SAMPLE_LABEL("storage", "Connection::initialize"); + +- int srv; +- nsresult rv; ++ // in memory database requested, sqlite uses a magic file name ++ int srv = ::sqlite3_open_v2(":memory:", &mDBConn, mFlags, NULL); ++ if (srv != SQLITE_OK) { ++ mDBConn = nullptr; ++ return convertResultCode(srv); ++ } ++ ++ return initializeInternal(nullptr); ++} ++ ++nsresult ++Connection::initialize(nsIFile *aDatabaseFile) ++{ ++ NS_ASSERTION (aDatabaseFile, "Passed null file!"); ++ NS_ASSERTION (!mDBConn, "Initialize called on already opened database!"); ++ SAMPLE_LABEL("storage", "Connection::initialize"); + + mDatabaseFile = aDatabaseFile; + +- if (aDatabaseFile) { +- nsAutoString path; +- rv = aDatabaseFile->GetPath(path); +- NS_ENSURE_SUCCESS(rv, rv); ++ nsAutoString path; ++ nsresult rv = aDatabaseFile->GetPath(path); ++ NS_ENSURE_SUCCESS(rv, rv); + +- srv = ::sqlite3_open_v2(NS_ConvertUTF16toUTF8(path).get(), &mDBConn, mFlags, +- aVFSName); +- } +- else { +- // in memory database requested, sqlite uses a magic file name +- srv = ::sqlite3_open_v2(":memory:", &mDBConn, mFlags, aVFSName); ++ int srv = ::sqlite3_open_v2(NS_ConvertUTF16toUTF8(path).get(), &mDBConn, ++ mFlags, NULL); ++ if (srv != SQLITE_OK) { ++ mDBConn = nullptr; ++ return convertResultCode(srv); + } ++ ++ rv = initializeInternal(aDatabaseFile); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ mDatabaseFile = aDatabaseFile; ++ ++ return NS_OK; ++} ++ ++nsresult ++Connection::initialize(nsIFileURL *aFileURL) ++{ ++ NS_ASSERTION (aFileURL, "Passed null file URL!"); ++ NS_ASSERTION (!mDBConn, "Initialize called on already opened database!"); ++ SAMPLE_LABEL("storage", "Connection::initialize"); ++ ++ nsCOMPtr<nsIFile> databaseFile; ++ nsresult rv = aFileURL->GetFile(getter_AddRefs(databaseFile)); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ nsAutoCString spec; ++ rv = aFileURL->GetSpec(spec); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ int srv = ::sqlite3_open_v2(spec.get(), &mDBConn, mFlags, NULL); + if (srv != SQLITE_OK) { + mDBConn = nullptr; + return convertResultCode(srv); + } + ++ rv = initializeInternal(databaseFile); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ mFileURL = aFileURL; ++ mDatabaseFile = databaseFile; ++ ++ return NS_OK; ++} ++ ++ ++nsresult ++Connection::initializeInternal(nsIFile* aDatabaseFile) ++{ + // Properly wrap the database handle's mutex. + sharedDBMutex.initWithMutex(sqlite3_db_mutex(mDBConn)); + +@@ -522,14 +572,14 @@ Connection::initialize(nsIFile *aDatabaseFile, + nsAutoCString pageSizeQuery(MOZ_STORAGE_UNIQUIFY_QUERY_STR + "PRAGMA page_size = "); + pageSizeQuery.AppendInt(pageSize); +- rv = ExecuteSimpleSQL(pageSizeQuery); ++ nsresult rv = ExecuteSimpleSQL(pageSizeQuery); + NS_ENSURE_SUCCESS(rv, rv); + + // Get the current page_size, since it may differ from the specified value. + sqlite3_stmt *stmt; + NS_NAMED_LITERAL_CSTRING(pragma_page_size, + MOZ_STORAGE_UNIQUIFY_QUERY_STR "PRAGMA page_size"); +- srv = prepareStatement(pragma_page_size, &stmt); ++ int srv = prepareStatement(pragma_page_size, &stmt); + if (srv == SQLITE_OK) { + if (SQLITE_ROW == stepStatement(stmt)) { + pageSize = ::sqlite3_column_int64(stmt, 0); +@@ -962,7 +1012,8 @@ Connection::Clone(bool aReadOnly, + nsRefPtr<Connection> clone = new Connection(mStorageService, flags); + NS_ENSURE_TRUE(clone, NS_ERROR_OUT_OF_MEMORY); + +- nsresult rv = clone->initialize(mDatabaseFile); ++ nsresult rv = mFileURL ? clone->initialize(mFileURL) ++ : clone->initialize(mDatabaseFile); + NS_ENSURE_SUCCESS(rv, rv); + + // Copy over pragmas from the original connection. +diff --git storage/src/mozStorageConnection.h storage/src/mozStorageConnection.h +index b71f5db..97f5cf8 100644 +--- storage/src/mozStorageConnection.h ++++ storage/src/mozStorageConnection.h +@@ -25,6 +25,7 @@ + + struct PRLock; + class nsIFile; ++class nsIFileURL; + class nsIEventTarget; + class nsIThread; + +@@ -63,18 +64,27 @@ public: + Connection(Service *aService, int aFlags); + + /** ++ * Creates the connection to an in-memory database. ++ */ ++ nsresult initialize(); ++ ++ /** + * Creates the connection to the database. + * + * @param aDatabaseFile + * The nsIFile of the location of the database to open, or create if it +- * does not exist. Passing in nullptr here creates an in-memory +- * database. +- * @param aVFSName +- * The VFS that SQLite will use when opening this database. NULL means +- * "default". ++ * does not exist. + */ +- nsresult initialize(nsIFile *aDatabaseFile, +- const char* aVFSName = NULL); ++ nsresult initialize(nsIFile *aDatabaseFile); ++ ++ /** ++ * Creates the connection to the database. ++ * ++ * @param aFileURL ++ * The nsIFileURL of the location of the database to open, or create if it ++ * does not exist. ++ */ ++ nsresult initialize(nsIFileURL *aFileURL); + + // fetch the native handle + sqlite3 *GetNativeConnection() { return mDBConn; } +@@ -155,6 +165,8 @@ public: + private: + ~Connection(); + ++ nsresult initializeInternal(nsIFile *aDatabaseFile); ++ + /** + * Sets the database into a closed state so no further actions can be + * performed. +@@ -206,6 +218,7 @@ private: + int progressHandler(); + + sqlite3 *mDBConn; ++ nsCOMPtr<nsIFileURL> mFileURL; + nsCOMPtr<nsIFile> mDatabaseFile; + + /** +diff --git storage/src/mozStorageService.cpp storage/src/mozStorageService.cpp +index 00661d6..862a7da 100644 +--- storage/src/mozStorageService.cpp ++++ storage/src/mozStorageService.cpp +@@ -24,8 +24,6 @@ + #include "mozilla/Preferences.h" + + #include "sqlite3.h" +-#include "test_quota.h" +-#include "test_quota.c" + + #ifdef SQLITE_OS_WIN + // "windows.h" was included and it can #define lots of things we care about... +@@ -35,61 +33,6 @@ + #include "nsIPromptService.h" + #include "nsIMemoryReporter.h" + +-namespace { +- +-class QuotaCallbackData +-{ +-public: +- QuotaCallbackData(mozIStorageQuotaCallback *aCallback, +- nsISupports *aUserData) +- : callback(aCallback), userData(aUserData) +- { +- MOZ_COUNT_CTOR(QuotaCallbackData); +- } +- +- ~QuotaCallbackData() +- { +- MOZ_COUNT_DTOR(QuotaCallbackData); +- } +- +- static void Callback(const char *zFilename, +- sqlite3_int64 *piLimit, +- sqlite3_int64 iSize, +- void *pArg) +- { +- NS_ASSERTION(zFilename && strlen(zFilename), "Null or empty filename!"); +- NS_ASSERTION(piLimit, "Null pointer!"); +- +- QuotaCallbackData *data = static_cast<QuotaCallbackData*>(pArg); +- if (!data) { +- // No callback specified, return immediately. +- return; +- } +- +- NS_ASSERTION(data->callback, "Should never have a null callback!"); +- +- nsDependentCString filename(zFilename); +- +- int64_t newLimit; +- if (NS_SUCCEEDED(data->callback->QuotaExceeded(filename, *piLimit, +- iSize, data->userData, +- &newLimit))) { +- *piLimit = newLimit; +- } +- } +- +- static void Destroy(void *aUserData) +- { +- delete static_cast<QuotaCallbackData*>(aUserData); +- } +- +-private: +- nsCOMPtr<mozIStorageQuotaCallback> callback; +- nsCOMPtr<nsISupports> userData; +-}; +- +-} // anonymous namespace +- + //////////////////////////////////////////////////////////////////////////////// + //// Defines + +@@ -345,11 +288,10 @@ private: + //////////////////////////////////////////////////////////////////////////////// + //// Service + +-NS_IMPL_THREADSAFE_ISUPPORTS3( ++NS_IMPL_THREADSAFE_ISUPPORTS2( + Service, + mozIStorageService, +- nsIObserver, +- mozIStorageServiceQuotaManagement ++ nsIObserver + ) + + Service *Service::gService = nullptr; +@@ -438,10 +380,6 @@ Service::~Service() + + // Shutdown the sqlite3 API. Warn if shutdown did not turn out okay, but + // there is nothing actionable we can do in that case. +- rc = ::sqlite3_quota_shutdown(); +- if (rc != SQLITE_OK) +- NS_WARNING("sqlite3 did not shutdown cleanly."); +- + rc = ::sqlite3_shutdown(); + if (rc != SQLITE_OK) + NS_WARNING("sqlite3 did not shutdown cleanly."); +@@ -636,9 +574,6 @@ Service::initialize() + } else { + NS_WARNING("Failed to register telemetry VFS"); + } +- rc = ::sqlite3_quota_initialize("telemetry-vfs", 0); +- if (rc != SQLITE_OK) +- return convertResultCode(rc); + + // Set the default value for the toolkit.storage.synchronous pref. It will be + // updated with the user preference on the main thread. +@@ -739,28 +674,24 @@ Service::OpenSpecialDatabase(const char *aStorageKey, + // connection to use a memory DB. + } + else if (::strcmp(aStorageKey, "profile") == 0) { +- + rv = NS_GetSpecialDirectory(NS_APP_STORAGE_50_FILE, + getter_AddRefs(storageFile)); + NS_ENSURE_SUCCESS(rv, rv); + +- nsString filename; +- storageFile->GetPath(filename); +- nsCString filename8 = NS_ConvertUTF16toUTF8(filename.get()); + // fall through to DB initialization + } + else { + return NS_ERROR_INVALID_ARG; + } + +- Connection *msc = new Connection(this, SQLITE_OPEN_READWRITE); +- NS_ENSURE_TRUE(msc, NS_ERROR_OUT_OF_MEMORY); ++ nsRefPtr<Connection> msc = new Connection(this, SQLITE_OPEN_READWRITE); + +- rv = msc->initialize(storageFile); ++ rv = storageFile ? msc->initialize(storageFile) : msc->initialize(); + NS_ENSURE_SUCCESS(rv, rv); + +- NS_ADDREF(*_connection = msc); ++ msc.forget(_connection); + return NS_OK; ++ + } + + NS_IMETHODIMP +@@ -774,12 +705,11 @@ Service::OpenDatabase(nsIFile *aDatabaseFile, + int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE | + SQLITE_OPEN_CREATE; + nsRefPtr<Connection> msc = new Connection(this, flags); +- NS_ENSURE_TRUE(msc, NS_ERROR_OUT_OF_MEMORY); + + nsresult rv = msc->initialize(aDatabaseFile); + NS_ENSURE_SUCCESS(rv, rv); + +- NS_ADDREF(*_connection = msc); ++ msc.forget(_connection); + return NS_OK; + } + +@@ -794,12 +724,30 @@ Service::OpenUnsharedDatabase(nsIFile *aDatabaseFile, + int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_PRIVATECACHE | + SQLITE_OPEN_CREATE; + nsRefPtr<Connection> msc = new Connection(this, flags); +- NS_ENSURE_TRUE(msc, NS_ERROR_OUT_OF_MEMORY); + + nsresult rv = msc->initialize(aDatabaseFile); + NS_ENSURE_SUCCESS(rv, rv); + +- NS_ADDREF(*_connection = msc); ++ msc.forget(_connection); ++ return NS_OK; ++} ++ ++NS_IMETHODIMP ++Service::OpenDatabaseWithFileURL(nsIFileURL *aFileURL, ++ mozIStorageConnection **_connection) ++{ ++ NS_ENSURE_ARG(aFileURL); ++ ++ // Always ensure that SQLITE_OPEN_CREATE is passed in for compatibility ++ // reasons. ++ int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE | ++ SQLITE_OPEN_CREATE | SQLITE_OPEN_URI; ++ nsRefPtr<Connection> msc = new Connection(this, flags); ++ ++ nsresult rv = msc->initialize(aFileURL); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ msc.forget(_connection); + return NS_OK; + } + +@@ -885,67 +833,5 @@ Service::Observe(nsISupports *, const char *aTopic, const PRUnichar *) + return NS_OK; + } + +-//////////////////////////////////////////////////////////////////////////////// +-//// mozIStorageServiceQuotaManagement +- +-NS_IMETHODIMP +-Service::OpenDatabaseWithVFS(nsIFile *aDatabaseFile, +- const nsACString &aVFSName, +- mozIStorageConnection **_connection) +-{ +- NS_ENSURE_ARG(aDatabaseFile); +- +- // Always ensure that SQLITE_OPEN_CREATE is passed in for compatibility +- // reasons. +- int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE | +- SQLITE_OPEN_CREATE; +- nsRefPtr<Connection> msc = new Connection(this, flags); +- NS_ENSURE_TRUE(msc, NS_ERROR_OUT_OF_MEMORY); +- +- nsresult rv = msc->initialize(aDatabaseFile, +- PromiseFlatCString(aVFSName).get()); +- NS_ENSURE_SUCCESS(rv, rv); +- +- NS_ADDREF(*_connection = msc); +- return NS_OK; +-} +- +-NS_IMETHODIMP +-Service::SetQuotaForFilenamePattern(const nsACString &aPattern, +- int64_t aSizeLimit, +- mozIStorageQuotaCallback *aCallback, +- nsISupports *aUserData) +-{ +- NS_ENSURE_FALSE(aPattern.IsEmpty(), NS_ERROR_INVALID_ARG); +- +- nsAutoPtr<QuotaCallbackData> data; +- if (aSizeLimit && aCallback) { +- data = new QuotaCallbackData(aCallback, aUserData); +- } +- +- int rc = ::sqlite3_quota_set(PromiseFlatCString(aPattern).get(), +- aSizeLimit, QuotaCallbackData::Callback, +- data, QuotaCallbackData::Destroy); +- NS_ENSURE_TRUE(rc == SQLITE_OK, convertResultCode(rc)); +- +- data.forget(); +- return NS_OK; +-} +- +-NS_IMETHODIMP +-Service::UpdateQuotaInformationForFile(nsIFile *aFile) +-{ +- NS_ENSURE_ARG_POINTER(aFile); +- +- nsString path; +- nsresult rv = aFile->GetPath(path); +- NS_ENSURE_SUCCESS(rv, rv); +- +- int rc = ::sqlite3_quota_file(NS_ConvertUTF16toUTF8(path).get()); +- NS_ENSURE_TRUE(rc == SQLITE_OK, convertResultCode(rc)); +- +- return NS_OK; +-} +- + } // namespace storage + } // namespace mozilla +diff --git storage/src/mozStorageService.h storage/src/mozStorageService.h +index 21c1ff8..3f5a546 100644 +--- storage/src/mozStorageService.h ++++ storage/src/mozStorageService.h +@@ -15,7 +15,6 @@ + #include "mozilla/Mutex.h" + + #include "mozIStorageService.h" +-#include "mozIStorageServiceQuotaManagement.h" + + class nsIMemoryReporter; + class nsIMemoryMultiReporter; +@@ -28,7 +27,6 @@ namespace storage { + class Connection; + class Service : public mozIStorageService + , public nsIObserver +- , public mozIStorageServiceQuotaManagement + { + public: + /** +@@ -58,7 +56,6 @@ public: + NS_DECL_ISUPPORTS + NS_DECL_MOZISTORAGESERVICE + NS_DECL_NSIOBSERVER +- NS_DECL_MOZISTORAGESERVICEQUOTAMANAGEMENT + + /** + * Obtains an already AddRefed pointer to XPConnect. This is used by +diff --git toolkit/toolkit-makefiles.sh toolkit/toolkit-makefiles.sh +index 6a7d714..8f1bbe0 100644 +--- toolkit/toolkit-makefiles.sh ++++ toolkit/toolkit-makefiles.sh +@@ -68,6 +68,7 @@ MAKEFILES_dom=" + dom/plugins/base/Makefile + dom/plugins/ipc/Makefile + dom/power/Makefile ++ dom/quota/Makefile + dom/settings/Makefile + dom/sms/Makefile + dom/sms/interfaces/Makefile Added: trunk/www/seamonkey/files/patch-bug787804 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ trunk/www/seamonkey/files/patch-bug787804 Wed Jan 2 19:58:18 2013 (r1130) @@ -0,0 +1,3557 @@ +commit 74997f1 +Author: Jan Varga <jan.varga@gmail.com> +Date: Mon Dec 17 20:25:10 2012 +0100 + + Bug 787804 - Rewrite quota handling (eliminate test_quota.c). r=bent,asuth,vladan +--- + db/sqlite3/README.MOZILLA | 4 +- + db/sqlite3/src/sqlite.def | 1 + + db/sqlite3/src/test_quota.c | 2001 -------------------- + db/sqlite3/src/test_quota.h | 274 --- + dom/Makefile.in | 1 + + dom/dom-config.mk | 1 + + dom/file/FileStreamWrappers.cpp | 11 - + dom/file/LockedFile.cpp | 8 +- + dom/file/nsIFileStorage.h | 40 +- + dom/indexedDB/FileManager.cpp | 33 +- + dom/indexedDB/FileManager.h | 20 +- + dom/indexedDB/FileStream.cpp | 321 ---- + dom/indexedDB/FileStream.h | 140 -- + dom/indexedDB/IDBDatabase.cpp | 6 + + dom/indexedDB/IDBFactory.cpp | 28 +- + dom/indexedDB/IDBFactory.h | 8 +- + dom/indexedDB/IDBFileHandle.cpp | 25 +- + dom/indexedDB/IDBObjectStore.cpp | 10 +- + dom/indexedDB/IDBTransaction.cpp | 3 +- + dom/indexedDB/IndexedDatabaseInlines.h | 13 + + dom/indexedDB/IndexedDatabaseManager.cpp | 162 +- + dom/indexedDB/IndexedDatabaseManager.h | 11 +- + dom/indexedDB/Makefile.in | 2 - + dom/indexedDB/OpenDatabaseHelper.cpp | 104 +- + dom/indexedDB/OpenDatabaseHelper.h | 12 +- + dom/indexedDB/nsIStandardFileStream.idl | 60 - + dom/indexedDB/test/Makefile.in | 2 + + dom/indexedDB/test/file.js | 21 +- + dom/indexedDB/test/test_file_quota.html | 14 +- + dom/indexedDB/test/test_filehandle_quota.html | 5 +- + dom/quota/FileStreams.cpp | 123 ++ + dom/quota/FileStreams.h | 115 ++ + dom/quota/Makefile.in | 33 + + dom/quota/QuotaCommon.h | 23 + + dom/quota/QuotaManager.cpp | 294 +++ + dom/quota/QuotaManager.h | 147 ++ + layout/build/Makefile.in | 1 + + netwerk/base/src/Makefile.in | 1 + + netwerk/base/src/nsFileStreams.cpp | 103 +- + netwerk/base/src/nsFileStreams.h | 12 +- + storage/public/Makefile.in | 1 - + storage/public/mozIStorageService.idl | 13 +- + .../public/mozIStorageServiceQuotaManagement.idl | 99 - + storage/public/storage.h | 1 - + storage/src/TelemetryVFS.cpp | 35 +- + storage/src/mozStorageConnection.cpp | 85 +- + storage/src/mozStorageConnection.h | 27 +- + storage/src/mozStorageService.cpp | 168 +- + storage/src/mozStorageService.h | 3 - + toolkit/toolkit-makefiles.sh | 1 + + 50 files changed, 1239 insertions(+), 3387 deletions(-) + +diff --git dom/Makefile.in dom/Makefile.in +index 672e065..47cd253 100644 +--- mozilla/dom/Makefile.in ++++ mozilla/dom/Makefile.in +@@ -58,6 +58,7 @@ PARALLEL_DIRS += \ + media \ + messages \ + power \ ++ quota \ + settings \ + sms \ + mms \ +diff --git dom/dom-config.mk dom/dom-config.mk +index d0f46cc..1cf57ed 100644 +--- mozilla/dom/dom-config.mk ++++ mozilla/dom/dom-config.mk +@@ -8,6 +8,7 @@ DOM_SRCDIRS = \ + dom/encoding \ + dom/file \ + dom/power \ ++ dom/quota \ + dom/media \ + dom/network/src \ + dom/settings \ +diff --git dom/file/FileStreamWrappers.cpp dom/file/FileStreamWrappers.cpp +index 2283266..c4cf102 100644 +--- mozilla/dom/file/FileStreamWrappers.cpp ++++ mozilla/dom/file/FileStreamWrappers.cpp +@@ -8,7 +8,6 @@ + + #include "nsIFileStorage.h" + #include "nsISeekableStream.h" +-#include "nsIStandardFileStream.h" + #include "mozilla/Attributes.h" + + #include "FileHelper.h" +@@ -246,16 +245,6 @@ FileOutputStreamWrapper::Close() + nsresult rv = NS_OK; + + if (!mFirstTime) { +- // We must flush buffers of the stream on the same thread on which we wrote +- // some data. +- nsCOMPtr<nsIStandardFileStream> sstream = do_QueryInterface(mFileStream); +- if (sstream) { +- rv = sstream->FlushBuffers(); +- if (NS_FAILED(rv)) { +- NS_WARNING("Failed to flush buffers of the stream!"); +- } +- } +- + NS_ASSERTION(PR_GetCurrentThread() == mWriteThread, + "Unsetting thread locals on wrong thread!"); + mFileHelper->mFileStorage->UnsetThreadLocals(); +diff --git dom/file/LockedFile.cpp dom/file/LockedFile.cpp +index 0fca730..926df91 100644 +--- mozilla/dom/file/LockedFile.cpp ++++ mozilla/dom/file/LockedFile.cpp +@@ -953,10 +953,10 @@ FinishHelper::Run() + } + + for (uint32_t index = 0; index < mParallelStreams.Length(); index++) { +- nsCOMPtr<nsIOutputStream> ostream = ++ nsCOMPtr<nsIInputStream> stream = + do_QueryInterface(mParallelStreams[index]); + +- if (NS_FAILED(ostream->Close())) { ++ if (NS_FAILED(stream->Close())) { + NS_WARNING("Failed to close stream!"); + } + +@@ -964,9 +964,9 @@ FinishHelper::Run() + } + + if (mStream) { +- nsCOMPtr<nsIOutputStream> ostream = do_QueryInterface(mStream); ++ nsCOMPtr<nsIInputStream> stream = do_QueryInterface(mStream); + +- if (NS_FAILED(ostream->Close())) { ++ if (NS_FAILED(stream->Close())) { + NS_WARNING("Failed to close stream!"); + } + +diff --git dom/file/nsIFileStorage.h dom/file/nsIFileStorage.h +index 92bb608..e985f0a 100644 +--- mozilla/dom/file/nsIFileStorage.h ++++ mozilla/dom/file/nsIFileStorage.h +@@ -10,14 +10,17 @@ + #include "nsISupports.h" + + #define NS_FILESTORAGE_IID \ +- {0xbba9c2ff, 0x85c9, 0x47c1, \ +- { 0xaf, 0xce, 0x0a, 0x7e, 0x6f, 0x21, 0x50, 0x95 } } ++ {0xa0801944, 0x2f1c, 0x4203, \ ++ { 0x9c, 0xaa, 0xaa, 0x47, 0xe0, 0x0c, 0x67, 0x92 } } + + class nsIFileStorage : public nsISupports + { + public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_FILESTORAGE_IID) + ++ virtual const nsACString& ++ StorageOrigin() = 0; ++ + virtual nsISupports* + StorageId() = 0; + +@@ -36,20 +39,23 @@ public: + + NS_DEFINE_STATIC_IID_ACCESSOR(nsIFileStorage, NS_FILESTORAGE_IID) + +-#define NS_DECL_NSIFILESTORAGE \ +- virtual nsISupports* \ +- StorageId(); \ +- \ +- virtual bool \ +- IsStorageInvalidated(); \ +- \ +- virtual bool \ +- IsStorageShuttingDown(); \ +- \ +- virtual void \ +- SetThreadLocals(); \ +- \ +- virtual void \ +- UnsetThreadLocals(); ++#define NS_DECL_NSIFILESTORAGE \ ++ virtual const nsACString& \ ++ StorageOrigin() MOZ_OVERRIDE; \ ++ \ ++ virtual nsISupports* \ ++ StorageId() MOZ_OVERRIDE; \ ++ \ ++ virtual bool \ ++ IsStorageInvalidated() MOZ_OVERRIDE; \ ++ \ ++ virtual bool \ ++ IsStorageShuttingDown() MOZ_OVERRIDE; \ ++ \ ++ virtual void \ ++ SetThreadLocals() MOZ_OVERRIDE; \ ++ \ ++ virtual void \ ++ UnsetThreadLocals() MOZ_OVERRIDE; + + #endif // nsIFileStorage_h__ +diff --git dom/indexedDB/FileManager.cpp dom/indexedDB/FileManager.cpp +index 9db56e8..4ed6e9e 100644 +--- mozilla/dom/indexedDB/FileManager.cpp ++++ mozilla/dom/indexedDB/FileManager.cpp +@@ -7,8 +7,8 @@ + #include "FileManager.h" + + #include "mozIStorageConnection.h" +-#include "mozIStorageServiceQuotaManagement.h" + #include "mozIStorageStatement.h" ++#include "nsIInputStream.h" + #include "nsISimpleEnumerator.h" + + #include "mozStorageCID.h" +@@ -18,6 +18,8 @@ + #include "IndexedDatabaseManager.h" + #include "OpenDatabaseHelper.h" + ++#include "IndexedDatabaseInlines.h" ++ + #define JOURNAL_DIRECTORY_NAME "journals" + + USING_INDEXEDDB_NAMESPACE +@@ -262,13 +264,11 @@ FileManager::GetFileForId(nsIFile* aDirectory, int64_t aId) + + // static + nsresult +-FileManager::InitDirectory(mozIStorageServiceQuotaManagement* aService, +- nsIFile* aDirectory, ++FileManager::InitDirectory(nsIFile* aDirectory, + nsIFile* aDatabaseFile, +- FactoryPrivilege aPrivilege) ++ const nsACString& aOrigin) + { + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); +- NS_ASSERTION(aService, "Null service!"); + NS_ASSERTION(aDirectory, "Null directory!"); + NS_ASSERTION(aDatabaseFile, "Null database file!"); + +@@ -310,8 +310,8 @@ FileManager::InitDirectory(mozIStorageServiceQuotaManagement* aService, + + if (hasElements) { + nsCOMPtr<mozIStorageConnection> connection; +- rv = OpenDatabaseHelper::CreateDatabaseConnection( +- NullString(), aDatabaseFile, aDirectory, getter_AddRefs(connection)); ++ rv = OpenDatabaseHelper::CreateDatabaseConnection(aDatabaseFile, ++ aDirectory, NullString(), aOrigin, getter_AddRefs(connection)); + NS_ENSURE_SUCCESS(rv, rv); + + mozStorageTransaction transaction(connection, false); +@@ -377,12 +377,17 @@ FileManager::InitDirectory(mozIStorageServiceQuotaManagement* aService, + } + } + +- if (aPrivilege == Chrome) { +- return NS_OK; +- } ++ return NS_OK; ++} ++ ++// static ++nsresult ++FileManager::GetUsage(nsIFile* aDirectory, uint64_t* aUsage) ++{ ++ uint64_t usage = 0; + + nsCOMPtr<nsISimpleEnumerator> entries; +- rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries)); ++ nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries)); + NS_ENSURE_SUCCESS(rv, rv); + + bool hasMore; +@@ -402,9 +407,13 @@ FileManager::InitDirectory(mozIStorageServiceQuotaManagement* aService, + continue; + } + +- rv = aService->UpdateQuotaInformationForFile(file); ++ int64_t fileSize; ++ rv = file->GetFileSize(&fileSize); + NS_ENSURE_SUCCESS(rv, rv); ++ ++ IncrementUsage(&usage, uint64_t(fileSize)); + } + ++ *aUsage = usage; + return NS_OK; + } +diff --git dom/indexedDB/FileManager.h dom/indexedDB/FileManager.h +index 2c72d0a..370d4a8 100644 +--- mozilla/dom/indexedDB/FileManager.h ++++ mozilla/dom/indexedDB/FileManager.h +@@ -24,10 +24,10 @@ class FileManager + friend class FileInfo; + + public: +- FileManager(const nsACString& aOrigin, ++ FileManager(const nsACString& aOrigin, FactoryPrivilege aPrivilege, + const nsAString& aDatabaseName) +- : mOrigin(aOrigin), mDatabaseName(aDatabaseName), mLastFileId(0), +- mInvalidated(false) ++ : mOrigin(aOrigin), mPrivilege(aPrivilege), mDatabaseName(aDatabaseName), ++ mLastFileId(0), mInvalidated(false) + { } + + ~FileManager() +@@ -40,6 +40,11 @@ public: + return mOrigin; + } + ++ const FactoryPrivilege& Privilege() const ++ { ++ return mPrivilege; ++ } ++ + const nsAString& DatabaseName() const + { + return mDatabaseName; +@@ -68,12 +73,15 @@ public: + static already_AddRefed<nsIFile> GetFileForId(nsIFile* aDirectory, + int64_t aId); + +- static nsresult InitDirectory(mozIStorageServiceQuotaManagement* aService, +- nsIFile* aDirectory, nsIFile* aDatabaseFile, +- FactoryPrivilege aPrivilege); ++ static nsresult InitDirectory(nsIFile* aDirectory, ++ nsIFile* aDatabaseFile, ++ const nsACString& aOrigin); ++ ++ static nsresult GetUsage(nsIFile* aDirectory, uint64_t* aUsage); + + private: + nsCString mOrigin; ++ FactoryPrivilege mPrivilege; + nsString mDatabaseName; + + nsString mDirectoryPath; +diff --git dom/indexedDB/FileStream.cpp dom/indexedDB/FileStream.cpp +deleted file mode 100644 +index dddf5d5..0000000 +--- mozilla/dom/indexedDB/FileStream.cpp ++++ /dev/null +@@ -1,321 +0,0 @@ +-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +-/* vim: set ts=2 et sw=2 tw=80: */ +-/* This Source Code Form is subject to the terms of the Mozilla Public +- * License, v. 2.0. If a copy of the MPL was not distributed with this file, +- * You can obtain one at http://mozilla.org/MPL/2.0/. */ +- +-#include "FileStream.h" +- +-#include "nsIFile.h" +- +-#include "nsThreadUtils.h" +-#include "test_quota.h" +- +-USING_INDEXEDDB_NAMESPACE +- +-NS_IMPL_THREADSAFE_ADDREF(FileStream) +-NS_IMPL_THREADSAFE_RELEASE(FileStream) +- +-NS_INTERFACE_MAP_BEGIN(FileStream) +- NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStandardFileStream) +- NS_INTERFACE_MAP_ENTRY(nsISeekableStream) +- NS_INTERFACE_MAP_ENTRY(nsIInputStream) +- NS_INTERFACE_MAP_ENTRY(nsIOutputStream) +- NS_INTERFACE_MAP_ENTRY(nsIStandardFileStream) +- NS_INTERFACE_MAP_ENTRY(nsIFileMetadata) +-NS_INTERFACE_MAP_END +- +-NS_IMETHODIMP +-FileStream::Seek(int32_t aWhence, int64_t aOffset) +-{ +- // TODO: Add support for 64 bit file sizes, bug 752431 +- NS_ENSURE_TRUE(aOffset <= INT32_MAX, NS_ERROR_INVALID_ARG); +- +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- int whence; +- switch (aWhence) { +- case nsISeekableStream::NS_SEEK_SET: +- whence = SEEK_SET; +- break; +- case nsISeekableStream::NS_SEEK_CUR: +- whence = SEEK_CUR; +- break; +- case nsISeekableStream::NS_SEEK_END: +- whence = SEEK_END; +- break; +- default: +- return NS_ERROR_INVALID_ARG; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- int rc = sqlite3_quota_fseek(mQuotaFile, aOffset, whence); +- NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR); +- +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::Tell(int64_t* aResult) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- long rc = sqlite3_quota_ftell(mQuotaFile); +- NS_ENSURE_TRUE(rc >= 0, NS_BASE_STREAM_OSERROR); +- +- *aResult = rc; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::SetEOF() +-{ +- int64_t pos; +- nsresult rv = Tell(&pos); +- NS_ENSURE_SUCCESS(rv, rv); +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- int rc = sqlite3_quota_ftruncate(mQuotaFile, pos); +- NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR); +- +- return NS_OK; +-} +- +- +-NS_IMETHODIMP +-FileStream::Close() +-{ +- CleanUpOpen(); +- +- if (mQuotaFile) { +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- int rc = sqlite3_quota_fclose(mQuotaFile); +- mQuotaFile = nullptr; +- +- NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR); +- } +- +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::Available(uint64_t* aResult) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- long rc = sqlite3_quota_file_available(mQuotaFile); +- NS_ENSURE_TRUE(rc >= 0, NS_BASE_STREAM_OSERROR); +- +- *aResult = rc; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::Read(char* aBuf, uint32_t aCount, uint32_t* aResult) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- size_t bytesRead = sqlite3_quota_fread(aBuf, 1, aCount, mQuotaFile); +- if (bytesRead < aCount && sqlite3_quota_ferror(mQuotaFile)) { +- return NS_BASE_STREAM_OSERROR; +- } +- +- *aResult = bytesRead; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, +- uint32_t aCount, uint32_t* aResult) +-{ +- NS_NOTREACHED("Don't call me!"); +- return NS_ERROR_NOT_IMPLEMENTED; +-} +- +-NS_IMETHODIMP +-FileStream::IsNonBlocking(bool *aNonBlocking) +-{ +- *aNonBlocking = false; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::Write(const char* aBuf, uint32_t aCount, uint32_t *aResult) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- size_t bytesWritten = sqlite3_quota_fwrite(aBuf, 1, aCount, mQuotaFile); +- if (bytesWritten < aCount) { +- return NS_BASE_STREAM_OSERROR; +- } +- +- *aResult = bytesWritten; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::Flush() +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- int rc = sqlite3_quota_fflush(mQuotaFile, 1); +- NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR); +- +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::WriteFrom(nsIInputStream *inStr, uint32_t count, uint32_t *_retval) +-{ +- return NS_ERROR_NOT_IMPLEMENTED; +-} +- +-NS_IMETHODIMP +-FileStream::WriteSegments(nsReadSegmentFun reader, void * closure, uint32_t count, uint32_t *_retval) +-{ +- NS_NOTREACHED("Don't call me!"); +- return NS_ERROR_NOT_IMPLEMENTED; +-} +- +-NS_IMETHODIMP +-FileStream::Init(nsIFile* aFile, const nsAString& aMode, int32_t aFlags) +-{ +- NS_ASSERTION(!mQuotaFile && !mDeferredOpen, "Already initialized!"); +- +- nsresult rv = aFile->GetPath(mFilePath); +- NS_ENSURE_SUCCESS(rv, rv); +- +- mMode = aMode; +- mFlags = aFlags; +- +- if (mFlags & nsIStandardFileStream::FLAGS_DEFER_OPEN) { +- mDeferredOpen = true; +- return NS_OK; +- } +- +- return DoOpen(); +-} +- +-NS_IMETHODIMP +-FileStream::GetSize(int64_t* _retval) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- // TODO: Use sqlite3_quota_file_size() here, bug 760783 +- int64_t rc = sqlite3_quota_file_truesize(mQuotaFile); +- +- NS_ASSERTION(rc >= 0, "The file is not under quota management!"); +- +- *_retval = rc; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::GetLastModified(int64_t* _retval) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- time_t mtime; +- int rc = sqlite3_quota_file_mtime(mQuotaFile, &mtime); +- NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR); +- +- *_retval = mtime * PR_MSEC_PER_SEC; +- return NS_OK; +-} +- +-NS_IMETHODIMP +-FileStream::FlushBuffers() +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mQuotaFile) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- int rc = sqlite3_quota_fflush(mQuotaFile, 0); +- NS_ENSURE_TRUE(rc == 0, NS_BASE_STREAM_OSERROR); +- +- return NS_OK; +-} +- +-nsresult +-FileStream::DoOpen() +-{ +- NS_ASSERTION(!mFilePath.IsEmpty(), "Must have a file path"); +- +- NS_ASSERTION(!NS_IsMainThread(), "Performing sync IO on the main thread!"); +- +- quota_FILE* quotaFile = +- sqlite3_quota_fopen(NS_ConvertUTF16toUTF8(mFilePath).get(), +- NS_ConvertUTF16toUTF8(mMode).get()); +- +- CleanUpOpen(); +- +- if (!quotaFile) { +- return NS_BASE_STREAM_OSERROR; +- } +- +- mQuotaFile = quotaFile; +- +- return NS_OK; +-} +diff --git dom/indexedDB/FileStream.h dom/indexedDB/FileStream.h +deleted file mode 100644 +index 09648b1..0000000 +--- mozilla/dom/indexedDB/FileStream.h ++++ /dev/null +@@ -1,140 +0,0 @@ +-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +-/* vim: set ts=2 et sw=2 tw=80: */ +-/* This Source Code Form is subject to the terms of the Mozilla Public +- * License, v. 2.0. If a copy of the MPL was not distributed with this file, +- * You can obtain one at http://mozilla.org/MPL/2.0/. */ +- +-#ifndef mozilla_dom_indexeddb_filestream_h__ +-#define mozilla_dom_indexeddb_filestream_h__ +- +-#include "IndexedDatabase.h" +- +-#include "nsIFileStreams.h" +-#include "nsIInputStream.h" +-#include "nsIOutputStream.h" +-#include "nsISeekableStream.h" +-#include "nsIStandardFileStream.h" +- +-class nsIFile; +-struct quota_FILE; +- +-BEGIN_INDEXEDDB_NAMESPACE +- +-class FileStream : public nsISeekableStream, +- public nsIInputStream, +- public nsIOutputStream, +- public nsIStandardFileStream, +- public nsIFileMetadata +-{ +-public: +- FileStream() +- : mFlags(0), +- mDeferredOpen(false), +- mQuotaFile(nullptr) +- { } +- +- virtual ~FileStream() +- { +- Close(); +- } +- +- NS_DECL_ISUPPORTS +- NS_DECL_NSISEEKABLESTREAM +- NS_DECL_NSISTANDARDFILESTREAM +- NS_DECL_NSIFILEMETADATA +- +- // nsIInputStream +- NS_IMETHOD +- Close(); +- +- NS_IMETHOD +- Available(uint64_t* _retval); +- +- NS_IMETHOD +- Read(char* aBuf, uint32_t aCount, uint32_t* _retval); +- +- NS_IMETHOD +- ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, uint32_t aCount, +- uint32_t* _retval); +- +- NS_IMETHOD +- IsNonBlocking(bool* _retval); +- +- // nsIOutputStream +- +- // Close() already declared +- +- NS_IMETHOD +- Flush(); +- +- NS_IMETHOD +- Write(const char* aBuf, uint32_t aCount, uint32_t* _retval); +- +- NS_IMETHOD +- WriteFrom(nsIInputStream* aFromStream, uint32_t aCount, uint32_t* _retval); +- +- NS_IMETHOD +- WriteSegments(nsReadSegmentFun aReader, void* aClosure, uint32_t aCount, +- uint32_t* _retval); +- +- // IsNonBlocking() already declared +- +-protected: +- /** +- * Cleans up data prepared in Init. +- */ +- void +- CleanUpOpen() +- { +- mFilePath.Truncate(); +- mDeferredOpen = false; +- } +- +- /** +- * Open the file. This is called either from Init +- * or from DoPendingOpen (if FLAGS_DEFER_OPEN is used when initializing this +- * stream). The default behavior of DoOpen is to open the file and save the +- * file descriptor. +- */ +- virtual nsresult +- DoOpen(); +- +- /** +- * If there is a pending open, do it now. It's important for this to be +- * inlined since we do it in almost every stream API call. +- */ +- nsresult +- DoPendingOpen() +- { +- if (!mDeferredOpen) { +- return NS_OK; +- } +- +- return DoOpen(); +- } +- +- /** +- * Data we need to do an open. +- */ +- nsString mFilePath; +- nsString mMode; +- +- /** +- * Flags describing our behavior. See the IDL file for possible values. +- */ +- int32_t mFlags; +- +- /** +- * Whether we have a pending open (see FLAGS_DEFER_OPEN in the IDL file). +- */ +- bool mDeferredOpen; +- +- /** +- * File descriptor for opened file. +- */ +- quota_FILE* mQuotaFile; +-}; +- +-END_INDEXEDDB_NAMESPACE +- +-#endif // mozilla_dom_indexeddb_filestream_h__ +diff --git dom/indexedDB/IDBDatabase.cpp dom/indexedDB/IDBDatabase.cpp +index 63500b0..8842daf 100644 +--- mozilla/dom/indexedDB/IDBDatabase.cpp ++++ mozilla/dom/indexedDB/IDBDatabase.cpp +@@ -779,6 +779,12 @@ IDBDatabase::Close() + return NS_OK; + } + ++const nsACString& ++IDBDatabase::StorageOrigin() ++{ ++ return Origin(); ++} ++ + nsISupports* + IDBDatabase::StorageId() + { +diff --git dom/indexedDB/IDBFactory.cpp dom/indexedDB/IDBFactory.cpp +index 1007df1..c1f573e 100644 +--- mozilla/dom/indexedDB/IDBFactory.cpp ++++ mozilla/dom/indexedDB/IDBFactory.cpp +@@ -253,8 +253,26 @@ IDBFactory::Create(ContentParent* aContentParent, + } + + // static ++already_AddRefed<nsIFileURL> ++IDBFactory::GetDatabaseFileURL(nsIFile* aDatabaseFile, const nsACString& aOrigin) ++{ ++ nsCOMPtr<nsIURI> uri; ++ nsresult rv = NS_NewFileURI(getter_AddRefs(uri), aDatabaseFile); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ ++ nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(uri); ++ NS_ASSERTION(fileUrl, "This should always succeed!"); ++ ++ rv = fileUrl->SetQuery(NS_LITERAL_CSTRING("origin=") + aOrigin); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ ++ return fileUrl.forget(); ++} ++ ++// static + already_AddRefed<mozIStorageConnection> +-IDBFactory::GetConnection(const nsAString& aDatabaseFilePath) ++IDBFactory::GetConnection(const nsAString& aDatabaseFilePath, ++ const nsACString& aOrigin) + { + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); + NS_ASSERTION(StringEndsWith(aDatabaseFilePath, NS_LITERAL_STRING(".sqlite")), +@@ -271,13 +289,15 @@ IDBFactory::GetConnection(const nsAString& aDatabaseFilePath) + NS_ENSURE_SUCCESS(rv, nullptr); + NS_ENSURE_TRUE(exists, nullptr); + +- nsCOMPtr<mozIStorageServiceQuotaManagement> ss = ++ nsCOMPtr<nsIFileURL> dbFileUrl = GetDatabaseFileURL(dbFile, aOrigin); ++ NS_ENSURE_TRUE(dbFileUrl, nullptr); ++ ++ nsCOMPtr<mozIStorageService> ss = + do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID); + NS_ENSURE_TRUE(ss, nullptr); + + nsCOMPtr<mozIStorageConnection> connection; +- rv = ss->OpenDatabaseWithVFS(dbFile, NS_LITERAL_CSTRING("quota"), +- getter_AddRefs(connection)); ++ rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(connection)); + NS_ENSURE_SUCCESS(rv, nullptr); + + // Turn on foreign key constraints and recursive triggers. +diff --git dom/indexedDB/IDBFactory.h dom/indexedDB/IDBFactory.h +index d5461f7..49dad42 100644 +--- mozilla/dom/indexedDB/IDBFactory.h ++++ mozilla/dom/indexedDB/IDBFactory.h +@@ -15,6 +15,8 @@ + #include "nsCycleCollectionParticipant.h" + + class nsIAtom; ++class nsIFile; ++class nsIFileURL; + class nsPIDOMWindow; + + namespace mozilla { +@@ -75,8 +77,12 @@ public: + static nsresult Create(ContentParent* aContentParent, + IDBFactory** aFactory); + ++ static already_AddRefed<nsIFileURL> ++ GetDatabaseFileURL(nsIFile* aDatabaseFile, const nsACString& aOrigin); ++ + static already_AddRefed<mozIStorageConnection> +- GetConnection(const nsAString& aDatabaseFilePath); ++ GetConnection(const nsAString& aDatabaseFilePath, ++ const nsACString& aOrigin); + + static nsresult + LoadDatabaseInformation(mozIStorageConnection* aConnection, +diff --git dom/indexedDB/IDBFileHandle.cpp dom/indexedDB/IDBFileHandle.cpp +index e0340ff..f71fd56 100644 +--- mozilla/dom/indexedDB/IDBFileHandle.cpp ++++ mozilla/dom/indexedDB/IDBFileHandle.cpp +@@ -6,15 +6,14 @@ + + #include "IDBFileHandle.h" + +-#include "nsIStandardFileStream.h" +- + #include "mozilla/dom/file/File.h" ++#include "mozilla/dom/quota/FileStreams.h" + #include "nsDOMClassInfoID.h" + +-#include "FileStream.h" + #include "IDBDatabase.h" + + USING_INDEXEDDB_NAMESPACE ++USING_QUOTA_NAMESPACE + + namespace { + +@@ -68,22 +67,22 @@ IDBFileHandle::Create(IDBDatabase* aDatabase, + already_AddRefed<nsISupports> + IDBFileHandle::CreateStream(nsIFile* aFile, bool aReadOnly) + { +- nsRefPtr<FileStream> stream = new FileStream(); ++ const nsACString& origin = mFileStorage->StorageOrigin(); ++ ++ nsCOMPtr<nsISupports> result; + +- nsString streamMode; + if (aReadOnly) { +- streamMode.AssignLiteral("rb"); ++ nsRefPtr<FileInputStream> stream = FileInputStream::Create( ++ origin, aFile, -1, -1, nsIFileInputStream::DEFER_OPEN); ++ result = NS_ISUPPORTS_CAST(nsIFileInputStream*, stream); + } + else { +- streamMode.AssignLiteral("r+b"); ++ nsRefPtr<FileStream> stream = FileStream::Create( ++ origin, aFile, -1, -1, nsIFileStream::DEFER_OPEN); ++ result = NS_ISUPPORTS_CAST(nsIFileStream*, stream); + } ++ NS_ENSURE_TRUE(result, nullptr); + +- nsresult rv = stream->Init(aFile, streamMode, +- nsIStandardFileStream::FLAGS_DEFER_OPEN); +- NS_ENSURE_SUCCESS(rv, nullptr); +- +- nsCOMPtr<nsISupports> result = +- NS_ISUPPORTS_CAST(nsIStandardFileStream*, stream); + return result.forget(); + } + +diff --git dom/indexedDB/IDBObjectStore.cpp dom/indexedDB/IDBObjectStore.cpp +index 746d473..1f16d26 100644 +--- mozilla/dom/indexedDB/IDBObjectStore.cpp ++++ mozilla/dom/indexedDB/IDBObjectStore.cpp +@@ -17,6 +17,7 @@ + #include "mozilla/dom/ContentParent.h" + #include "mozilla/dom/StructuredCloneTags.h" + #include "mozilla/dom/ipc/Blob.h" ++#include "mozilla/dom/quota/FileStreams.h" + #include "mozilla/storage.h" + #include "nsContentUtils.h" + #include "nsDOMClassInfo.h" +@@ -27,10 +28,8 @@ + #include "nsServiceManagerUtils.h" + #include "nsThreadUtils.h" + #include "snappy/snappy.h" +-#include "test_quota.h" + + #include "AsyncConnectionHelper.h" +-#include "FileStream.h" + #include "IDBCursor.h" + #include "IDBEvents.h" + #include "IDBFileHandle.h" +@@ -51,6 +50,7 @@ + USING_INDEXEDDB_NAMESPACE + using namespace mozilla::dom; + using namespace mozilla::dom::indexedDB::ipc; ++using mozilla::dom::quota::FileOutputStream; + + namespace { + +@@ -2734,9 +2734,9 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection) + nativeFile = fileManager->GetFileForId(directory, id); + NS_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- nsRefPtr<FileStream> outputStream = new FileStream(); +- rv = outputStream->Init(nativeFile, NS_LITERAL_STRING("wb"), 0); +- NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); ++ nsRefPtr<FileOutputStream> outputStream = FileOutputStream::Create( ++ mObjectStore->Transaction()->Database()->Origin(), nativeFile); ++ NS_ENSURE_TRUE(outputStream, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + rv = CopyData(inputStream, outputStream); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); +diff --git dom/indexedDB/IDBTransaction.cpp dom/indexedDB/IDBTransaction.cpp +index fcef7cc..a5345e2 100644 +--- mozilla/dom/indexedDB/IDBTransaction.cpp ++++ mozilla/dom/indexedDB/IDBTransaction.cpp +@@ -352,7 +352,8 @@ IDBTransaction::GetOrCreateConnection(mozIStorageConnection** aResult) + + if (!mConnection) { + nsCOMPtr<mozIStorageConnection> connection = +- IDBFactory::GetConnection(mDatabase->FilePath()); ++ IDBFactory::GetConnection(mDatabase->FilePath(), ++ mDatabase->Origin()); + NS_ENSURE_TRUE(connection, NS_ERROR_FAILURE); + + nsresult rv; +diff --git dom/indexedDB/IndexedDatabaseInlines.h dom/indexedDB/IndexedDatabaseInlines.h +index 62e65d6..f27d60c 100644 +--- mozilla/dom/indexedDB/IndexedDatabaseInlines.h ++++ mozilla/dom/indexedDB/IndexedDatabaseInlines.h +@@ -79,4 +79,17 @@ AppendConditionClause(const nsACString& aColumnName, + aResult += NS_LITERAL_CSTRING(" :") + aArgName; + } + ++inline void ++IncrementUsage(uint64_t* aUsage, uint64_t aDelta) ++{ ++ // Watch for overflow! ++ if ((UINT64_MAX - *aUsage) < aDelta) { ++ NS_WARNING("Usage exceeds the maximum!"); ++ *aUsage = UINT64_MAX; ++ } ++ else { ++ *aUsage += aDelta; ++ } ++} ++ + END_INDEXEDDB_NAMESPACE +diff --git dom/indexedDB/IndexedDatabaseManager.cpp dom/indexedDB/IndexedDatabaseManager.cpp +index e4ad647..88f09da 100644 +--- mozilla/dom/indexedDB/IndexedDatabaseManager.cpp ++++ mozilla/dom/indexedDB/IndexedDatabaseManager.cpp +@@ -22,6 +22,7 @@ + #include "nsITimer.h" + + #include "mozilla/dom/file/FileService.h" ++#include "mozilla/dom/quota/QuotaManager.h" + #include "mozilla/dom/TabContext.h" + #include "mozilla/LazyIdleThread.h" + #include "mozilla/Preferences.h" +@@ -36,7 +37,6 @@ + #include "nsThreadUtils.h" + #include "nsXPCOM.h" + #include "nsXPCOMPrivate.h" +-#include "test_quota.h" + #include "xpcpublic.h" + + #include "AsyncConnectionHelper.h" +@@ -48,6 +48,8 @@ + #include "OpenDatabaseHelper.h" + #include "TransactionThreadPool.h" + ++#include "IndexedDatabaseInlines.h" ++ + // The amount of time, in milliseconds, that our IO thread will stay alive + // after the last event it processes. + #define DEFAULT_THREAD_TIMEOUT_MS 30000 +@@ -70,6 +72,7 @@ using namespace mozilla::services; + using namespace mozilla::dom; + using mozilla::Preferences; + using mozilla::dom::file::FileService; ++using mozilla::dom::quota::QuotaManager; + + static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID); + +@@ -103,29 +106,6 @@ GetDatabaseBaseFilename(const nsAString& aFilename, + return true; + } + +-class QuotaCallback MOZ_FINAL : public mozIStorageQuotaCallback +-{ +-public: +- NS_DECL_ISUPPORTS +- +- NS_IMETHOD +- QuotaExceeded(const nsACString& aFilename, +- int64_t aCurrentSizeLimit, +- int64_t aCurrentTotalSize, +- nsISupports* aUserData, +- int64_t* _retval) +- { +- if (IndexedDatabaseManager::QuotaIsLifted()) { +- *_retval = 0; +- return NS_OK; +- } +- +- return NS_ERROR_FAILURE; +- } +-}; +- +-NS_IMPL_THREADSAFE_ISUPPORTS1(QuotaCallback, mozIStorageQuotaCallback) +- + // Adds all databases in the hash to the given array. + template <class T> + PLDHashOperator +@@ -440,8 +420,8 @@ IndexedDatabaseManager::GetOrCreate() + NS_LITERAL_CSTRING("IndexedDB I/O"), + LazyIdleThread::ManualShutdown); + +- // We need one quota callback object to hand to SQLite. +- instance->mQuotaCallbackSingleton = new QuotaCallback(); ++ // Make sure that the quota manager is up. ++ NS_ENSURE_TRUE(QuotaManager::GetOrCreate(), nullptr); + + // Make a timer here to avoid potential failures later. We don't actually + // initialize the timer until shutdown. +@@ -996,37 +976,15 @@ IndexedDatabaseManager::EnsureOriginIsInitialized(const nsACString& aOrigin, + return NS_OK; + } + +- // First figure out the filename pattern we'll use. +- nsCOMPtr<nsIFile> patternFile; +- rv = directory->Clone(getter_AddRefs(patternFile)); +- NS_ENSURE_SUCCESS(rv, rv); +- +- rv = patternFile->Append(NS_LITERAL_STRING("*")); +- NS_ENSURE_SUCCESS(rv, rv); +- +- nsString pattern; +- rv = patternFile->GetPath(pattern); +- NS_ENSURE_SUCCESS(rv, rv); +- +- // Now tell SQLite to start tracking this pattern for content. +- nsCOMPtr<mozIStorageServiceQuotaManagement> ss = +- do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID); +- NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE); +- +- if (aPrivilege != Chrome) { +- rv = ss->SetQuotaForFilenamePattern(NS_ConvertUTF16toUTF8(pattern), +- GetIndexedDBQuotaMB() * 1024 * 1024, +- mQuotaCallbackSingleton, nullptr); +- NS_ENSURE_SUCCESS(rv, rv); +- } +- + // We need to see if there are any files in the directory already. If they + // are database files then we need to cleanup stored files (if it's needed) +- // and also tell SQLite about all of them. ++ // and also initialize the quota. + + nsAutoTArray<nsString, 20> subdirsToProcess; + nsAutoTArray<nsCOMPtr<nsIFile> , 20> unknownFiles; + ++ uint64_t usage = 0; ++ + nsTHashtable<nsStringHashKey> validSubdirs; + validSubdirs.Init(20); + +@@ -1068,20 +1026,28 @@ IndexedDatabaseManager::EnsureOriginIsInitialized(const nsACString& aOrigin, + continue; + } + +- nsCOMPtr<nsIFile> fileManagerDirectory; +- rv = directory->Clone(getter_AddRefs(fileManagerDirectory)); ++ nsCOMPtr<nsIFile> fmDirectory; ++ rv = directory->Clone(getter_AddRefs(fmDirectory)); + NS_ENSURE_SUCCESS(rv, rv); + +- rv = fileManagerDirectory->Append(dbBaseFilename); ++ rv = fmDirectory->Append(dbBaseFilename); + NS_ENSURE_SUCCESS(rv, rv); + +- rv = FileManager::InitDirectory(ss, fileManagerDirectory, file, +- aPrivilege); ++ rv = FileManager::InitDirectory(fmDirectory, file, aOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + if (aPrivilege != Chrome) { +- rv = ss->UpdateQuotaInformationForFile(file); ++ uint64_t fileUsage; ++ rv = FileManager::GetUsage(fmDirectory, &fileUsage); + NS_ENSURE_SUCCESS(rv, rv); ++ ++ IncrementUsage(&usage, fileUsage); ++ ++ int64_t fileSize; ++ rv = file->GetFileSize(&fileSize); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ IncrementUsage(&usage, uint64_t(fileSize)); + } + + validSubdirs.PutEntry(dbBaseFilename); +@@ -1117,12 +1083,39 @@ IndexedDatabaseManager::EnsureOriginIsInitialized(const nsACString& aOrigin, + } + } + ++ if (aPrivilege != Chrome) { ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ quotaManager->InitQuotaForOrigin(aOrigin, GetIndexedDBQuotaMB(), usage); ++ } ++ + mInitializedOrigins.AppendElement(aOrigin); + + NS_ADDREF(*aDirectory = directory); + return NS_OK; + } + ++void ++IndexedDatabaseManager::UninitializeOriginsByPattern( ++ const nsACString& aPattern) ++{ ++#ifdef DEBUG ++ { ++ bool correctThread; ++ NS_ASSERTION(NS_SUCCEEDED(mIOThread->IsOnCurrentThread(&correctThread)) && ++ correctThread, ++ "Running on the wrong thread!"); ++ } ++#endif ++ ++ for (int32_t i = mInitializedOrigins.Length() - 1; i >= 0; i--) { ++ if (PatternMatchesOrigin(aPattern, mInitializedOrigins[i])) { ++ mInitializedOrigins.RemoveElementAt(i); ++ } ++ } ++} ++ + bool + IndexedDatabaseManager::QuotaIsLiftedInternal() + { +@@ -1250,16 +1243,14 @@ IndexedDatabaseManager::GetFileManager(const nsACString& aOrigin, + } + + void +-IndexedDatabaseManager::AddFileManager(const nsACString& aOrigin, +- const nsAString& aDatabaseName, +- FileManager* aFileManager) ++IndexedDatabaseManager::AddFileManager(FileManager* aFileManager) + { + NS_ASSERTION(aFileManager, "Null file manager!"); + + nsTArray<nsRefPtr<FileManager> >* array; +- if (!mFileManagers.Get(aOrigin, &array)) { ++ if (!mFileManagers.Get(aFileManager->Origin(), &array)) { + array = new nsTArray<nsRefPtr<FileManager> >(); +- mFileManagers.Put(aOrigin, array); ++ mFileManagers.Put(aFileManager->Origin(), array); + } + + array->AppendElement(aFileManager); +@@ -1783,6 +1774,13 @@ OriginClearRunnable::DeleteFiles(IndexedDatabaseManager* aManager) + // correctly... + NS_ERROR("Failed to remove directory!"); + } ++ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ quotaManager->RemoveQuotaForPattern(mOriginOrPattern); ++ ++ aManager->UninitializeOriginsByPattern(mOriginOrPattern); + } + } + +@@ -1880,19 +1878,6 @@ IndexedDatabaseManager::AsyncUsageRunnable::Cancel() + } + } + +-inline void +-IncrementUsage(uint64_t* aUsage, uint64_t aDelta) +-{ +- // Watch for overflow! +- if ((INT64_MAX - *aUsage) <= aDelta) { +- NS_WARNING("Database sizes exceed max we can report!"); +- *aUsage = INT64_MAX; +- } +- else { +- *aUsage += aDelta; +- } +-} +- + nsresult + IndexedDatabaseManager::AsyncUsageRunnable::TakeShortcut() + { +@@ -2295,25 +2280,22 @@ IndexedDatabaseManager::AsyncDeleteFileRunnable::Run() + nsCOMPtr<nsIFile> file = mFileManager->GetFileForId(directory, mFileId); + NS_ENSURE_TRUE(file, NS_ERROR_FAILURE); + +- nsString filePath; +- nsresult rv = file->GetPath(filePath); +- NS_ENSURE_SUCCESS(rv, rv); ++ nsresult rv; ++ int64_t fileSize; + +- int rc = sqlite3_quota_remove(NS_ConvertUTF16toUTF8(filePath).get()); +- if (rc != SQLITE_OK) { +- NS_WARNING("Failed to delete stored file!"); +- return NS_ERROR_FAILURE; ++ if (mFileManager->Privilege() != Chrome) { ++ rv = file->GetFileSize(&fileSize); ++ NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); + } + +- // sqlite3_quota_remove won't actually remove anything if we're not tracking +- // the quota here. Manually remove the file if it exists. +- bool exists; +- rv = file->Exists(&exists); +- NS_ENSURE_SUCCESS(rv, rv); ++ rv = file->Remove(false); ++ NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); + +- if (exists) { +- rv = file->Remove(false); +- NS_ENSURE_SUCCESS(rv, rv); ++ if (mFileManager->Privilege() != Chrome) { ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ quotaManager->DecreaseUsageForOrigin(mFileManager->Origin(), fileSize); + } + + directory = mFileManager->GetJournalDirectory(); +diff --git dom/indexedDB/IndexedDatabaseManager.h dom/indexedDB/IndexedDatabaseManager.h +index f9fbbf2..1ea5425 100644 +--- mozilla/dom/indexedDB/IndexedDatabaseManager.h ++++ mozilla/dom/indexedDB/IndexedDatabaseManager.h +@@ -23,7 +23,6 @@ + + #define INDEXEDDB_MANAGER_CONTRACTID "@mozilla.org/dom/indexeddb/manager;1" + +-class mozIStorageQuotaCallback; + class nsIAtom; + class nsIFile; + class nsITimer; +@@ -134,6 +133,8 @@ public: + FactoryPrivilege aPrivilege, + nsIFile** aDirectory); + ++ void UninitializeOriginsByPattern(const nsACString& aPattern); ++ + // Determine if the quota is lifted for the Window the current thread is + // using. + static inline bool +@@ -172,9 +173,7 @@ public: + const nsAString& aDatabaseName); + + void +- AddFileManager(const nsACString& aOrigin, +- const nsAString& aDatabaseName, +- FileManager* aFileManager); ++ AddFileManager(FileManager* aFileManager); + + void InvalidateFileManagersForPattern(const nsACString& aPattern); + +@@ -502,10 +501,6 @@ private: + // A timer that gets activated at shutdown to ensure we close all databases. + nsCOMPtr<nsITimer> mShutdownTimer; + +- // A single threadsafe instance of our quota callback. Created on the main +- // thread during GetOrCreate(). +- nsCOMPtr<mozIStorageQuotaCallback> mQuotaCallbackSingleton; +- + // A list of all successfully initialized origins. This list isn't protected + // by any mutex but it is only ever touched on the IO thread. + nsTArray<nsCString> mInitializedOrigins; +diff --git dom/indexedDB/Makefile.in dom/indexedDB/Makefile.in +index fef0858..09d4853 100644 +--- mozilla/dom/indexedDB/Makefile.in ++++ mozilla/dom/indexedDB/Makefile.in +@@ -25,7 +25,6 @@ CPPSRCS = \ + DatabaseInfo.cpp \ + FileInfo.cpp \ + FileManager.cpp \ +- FileStream.cpp \ + IDBCursor.cpp \ + IDBDatabase.cpp \ + IDBEvents.cpp \ +@@ -93,7 +92,6 @@ XPIDLSRCS = \ + nsIIDBVersionChangeEvent.idl \ + nsIIDBOpenDBRequest.idl \ + nsIIndexedDatabaseManager.idl \ +- nsIStandardFileStream.idl \ + $(NULL) + + DIRS += ipc +diff --git dom/indexedDB/OpenDatabaseHelper.cpp dom/indexedDB/OpenDatabaseHelper.cpp +index e71cad4..4cd7f61 100644 +--- mozilla/dom/indexedDB/OpenDatabaseHelper.cpp ++++ mozilla/dom/indexedDB/OpenDatabaseHelper.cpp +@@ -8,11 +8,12 @@ + + #include "nsIFile.h" + ++#include "mozilla/dom/quota/QuotaManager.h" + #include "mozilla/storage.h" + #include "nsEscape.h" ++#include "nsNetUtil.h" + #include "nsThreadUtils.h" + #include "snappy/snappy.h" +-#include "test_quota.h" + + #include "nsIBFCacheEntry.h" + #include "IDBEvents.h" +@@ -21,6 +22,7 @@ + + using namespace mozilla; + USING_INDEXEDDB_NAMESPACE ++USING_QUOTA_NAMESPACE + + namespace { + +@@ -1632,15 +1634,15 @@ OpenDatabaseHelper::DoDatabaseWork() + rv = dbFile->GetPath(mDatabaseFilePath); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- nsCOMPtr<nsIFile> fileManagerDirectory; +- rv = dbDirectory->Clone(getter_AddRefs(fileManagerDirectory)); ++ nsCOMPtr<nsIFile> fmDirectory; ++ rv = dbDirectory->Clone(getter_AddRefs(fmDirectory)); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- rv = fileManagerDirectory->Append(filename); ++ rv = fmDirectory->Append(filename); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + nsCOMPtr<mozIStorageConnection> connection; +- rv = CreateDatabaseConnection(mName, dbFile, fileManagerDirectory, ++ rv = CreateDatabaseConnection(dbFile, fmDirectory, mName, mASCIIOrigin, + getter_AddRefs(connection)); + if (NS_FAILED(rv) && + NS_ERROR_GET_MODULE(rv) != NS_ERROR_MODULE_DOM_INDEXEDDB) { +@@ -1691,12 +1693,12 @@ OpenDatabaseHelper::DoDatabaseWork() + + nsRefPtr<FileManager> fileManager = mgr->GetFileManager(mASCIIOrigin, mName); + if (!fileManager) { +- fileManager = new FileManager(mASCIIOrigin, mName); ++ fileManager = new FileManager(mASCIIOrigin, mPrivilege, mName); + +- rv = fileManager->Init(fileManagerDirectory, connection); ++ rv = fileManager->Init(fmDirectory, connection); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- mgr->AddFileManager(mASCIIOrigin, mName, fileManager); ++ mgr->AddFileManager(fileManager); + } + + mFileManager = fileManager.forget(); +@@ -1707,23 +1709,26 @@ OpenDatabaseHelper::DoDatabaseWork() + // static + nsresult + OpenDatabaseHelper::CreateDatabaseConnection( +- const nsAString& aName, + nsIFile* aDBFile, +- nsIFile* aFileManagerDirectory, ++ nsIFile* aFMDirectory, ++ const nsAString& aName, ++ const nsACString& aOrigin, + mozIStorageConnection** aConnection) + { + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); + +- NS_NAMED_LITERAL_CSTRING(quotaVFSName, "quota"); ++ nsCOMPtr<nsIFileURL> dbFileUrl = ++ IDBFactory::GetDatabaseFileURL(aDBFile, aOrigin); ++ NS_ENSURE_TRUE(dbFileUrl, NS_ERROR_FAILURE); + +- nsCOMPtr<mozIStorageServiceQuotaManagement> ss = ++ nsCOMPtr<mozIStorageService> ss = + do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID); + NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE); + + nsCOMPtr<mozIStorageConnection> connection; +- nsresult rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName, +- getter_AddRefs(connection)); ++ nsresult rv = ++ ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(connection)); + if (rv == NS_ERROR_FILE_CORRUPTED) { + // If we're just opening the database during origin initialization, then + // we don't want to erase any files. The failure here will fail origin +@@ -1737,21 +1742,20 @@ OpenDatabaseHelper::CreateDatabaseConnection( + NS_ENSURE_SUCCESS(rv, rv); + + bool exists; +- rv = aFileManagerDirectory->Exists(&exists); ++ rv = aFMDirectory->Exists(&exists); + NS_ENSURE_SUCCESS(rv, rv); + + if (exists) { + bool isDirectory; +- rv = aFileManagerDirectory->IsDirectory(&isDirectory); ++ rv = aFMDirectory->IsDirectory(&isDirectory); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- rv = aFileManagerDirectory->Remove(true); ++ rv = aFMDirectory->Remove(true); + NS_ENSURE_SUCCESS(rv, rv); + } + +- rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName, +- getter_AddRefs(connection)); ++ rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(connection)); + } + NS_ENSURE_SUCCESS(rv, rv); + +@@ -2347,6 +2351,8 @@ DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection) + { + NS_ASSERTION(!aConnection, "How did we get a connection here?"); + ++ const FactoryPrivilege& privilege = mOpenHelper->Privilege(); ++ + IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get(); + NS_ASSERTION(mgr, "This should never fail!"); + +@@ -2372,59 +2378,57 @@ DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection) + rv = dbFile->Exists(&exists); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- int rc; +- + if (exists) { +- nsString dbFilePath; +- rv = dbFile->GetPath(dbFilePath); +- NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); ++ int64_t fileSize; + +- rc = sqlite3_quota_remove(NS_ConvertUTF16toUTF8(dbFilePath).get()); +- if (rc != SQLITE_OK) { +- NS_WARNING("Failed to delete db file!"); +- return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; ++ if (privilege != Chrome) { ++ rv = dbFile->GetFileSize(&fileSize); ++ NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + } + +- // sqlite3_quota_remove won't actually remove anything if we're not tracking +- // the quota here. Manually remove the file if it exists. +- rv = dbFile->Exists(&exists); ++ rv = dbFile->Remove(false); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- if (exists) { +- rv = dbFile->Remove(false); +- NS_ENSURE_SUCCESS(rv, rv); ++ if (privilege != Chrome) { ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ quotaManager->DecreaseUsageForOrigin(mASCIIOrigin, fileSize); + } + } + +- nsCOMPtr<nsIFile> fileManagerDirectory; +- rv = directory->Clone(getter_AddRefs(fileManagerDirectory)); +- NS_ENSURE_SUCCESS(rv, rv); ++ nsCOMPtr<nsIFile> fmDirectory; ++ rv = directory->Clone(getter_AddRefs(fmDirectory)); ++ NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- rv = fileManagerDirectory->Append(filename); ++ rv = fmDirectory->Append(filename); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- rv = fileManagerDirectory->Exists(&exists); ++ rv = fmDirectory->Exists(&exists); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + if (exists) { + bool isDirectory; +- rv = fileManagerDirectory->IsDirectory(&isDirectory); ++ rv = fmDirectory->IsDirectory(&isDirectory); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + +- nsString fileManagerDirectoryPath; +- rv = fileManagerDirectory->GetPath(fileManagerDirectoryPath); +- NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); ++ uint64_t usage = 0; + +- rc = sqlite3_quota_remove( +- NS_ConvertUTF16toUTF8(fileManagerDirectoryPath).get()); +- if (rc != SQLITE_OK) { +- NS_WARNING("Failed to delete file directory!"); +- return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; ++ if (privilege != Chrome) { ++ rv = FileManager::GetUsage(fmDirectory, &usage); ++ NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + } + +- rv = fileManagerDirectory->Remove(true); +- NS_ENSURE_SUCCESS(rv, rv); ++ rv = fmDirectory->Remove(true); ++ NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); ++ ++ if (privilege != Chrome) { ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ quotaManager->DecreaseUsageForOrigin(mASCIIOrigin, usage); ++ } + } + + return NS_OK; +diff --git dom/indexedDB/OpenDatabaseHelper.h dom/indexedDB/OpenDatabaseHelper.h +index 587301b..5a3d987 100644 +--- mozilla/dom/indexedDB/OpenDatabaseHelper.h ++++ mozilla/dom/indexedDB/OpenDatabaseHelper.h +@@ -77,10 +77,16 @@ public: + return mDatabase; + } + ++ const FactoryPrivilege& Privilege() const ++ { ++ return mPrivilege; ++ } ++ + static +- nsresult CreateDatabaseConnection(const nsAString& aName, +- nsIFile* aDBFile, +- nsIFile* aFileManagerDirectory, ++ nsresult CreateDatabaseConnection(nsIFile* aDBFile, ++ nsIFile* aFMDirectory, ++ const nsAString& aName, ++ const nsACString& aOrigin, + mozIStorageConnection** aConnection); + + protected: +diff --git dom/indexedDB/nsIStandardFileStream.idl dom/indexedDB/nsIStandardFileStream.idl +deleted file mode 100644 +index 265c3ed..0000000 +--- mozilla/dom/indexedDB/nsIStandardFileStream.idl ++++ /dev/null +@@ -1,60 +0,0 @@ +-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +-/* vim: set ts=2 et sw=2 tw=80: */ +-/* This Source Code Form is subject to the terms of the Mozilla Public +- * License, v. 2.0. If a copy of the MPL was not distributed with this file, +- * You can obtain one at http://mozilla.org/MPL/2.0/. */ +- +-#include "nsISupports.idl" +- +-interface nsIFile; +- +-/** +- * A stream that allows you to read from a file or stream to a file +- * using standard file APIs. +- */ +-[scriptable, uuid(ebbbb779-92a3-4b2a-b7cf-6efbe904c453)] +-interface nsIStandardFileStream : nsISupports +-{ +- /** +- * If this is set, the file will be opened (i.e., a call to +- * fopen done) only when we do an actual operation on the stream, +- * or more specifically, when one of the following is called: +- * - Seek +- * - Tell +- * - SetEOF +- * - Available +- * - Read +- * - Write +- * - Flush +- * - GetSize +- * - GetLastModified +- * - Sync +- * +- * FLAGS_DEFER_OPEN is useful if we use the stream on a background +- * thread, so that the opening and possible |stat|ing of the file +- * happens there as well. +- * +- * @note Using this flag results in the file not being opened +- * during the call to Init. This means that any errors that might +- * happen when this flag is not set would happen during the +- * first read. Also, the file is not locked when Init is called, +- * so it might be deleted before we try to read from it. +- */ +- const long FLAGS_DEFER_OPEN = 1 << 0; +- +- /** +- * @param file file to read from or stream to +- * @param mode file open mode (see fopen documentation) +- * @param flags flags specifying various behaviors of the class +- * (see enumerations in the class) +- */ +- void init(in nsIFile file, +- in AString mode, +- in long flags); +- +- /** +- * Flush all written content held in memory buffers out to disk. +- * This is the equivalent of fflush() +- */ +- void flushBuffers(); +-}; +diff --git dom/indexedDB/test/Makefile.in dom/indexedDB/test/Makefile.in +index 9c79b14..4c9a201 100644 +--- mozilla/dom/indexedDB/test/Makefile.in ++++ mozilla/dom/indexedDB/test/Makefile.in +@@ -54,11 +54,13 @@ MOCHITEST_FILES = \ + test_file_os_delete.html \ + test_file_put_get_object.html \ + test_file_put_get_values.html \ ++ test_file_quota.html \ + test_file_replace.html \ + test_file_resurrection_delete.html \ + test_file_resurrection_transaction_abort.html \ + test_file_sharing.html \ + test_file_transaction_abort.html \ ++ test_filehandle_quota.html \ + test_filehandle_serialization.html \ + test_filehandle_store_snapshot.html \ + test_getAll.html \ +diff --git dom/indexedDB/test/file.js dom/indexedDB/test/file.js +index 07bd10a..3c6194a 100644 +--- mozilla/dom/indexedDB/test/file.js ++++ mozilla/dom/indexedDB/test/file.js +@@ -3,6 +3,8 @@ + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + ++const DEFAULT_QUOTA = 50 * 1024 * 1024; ++ + var bufferCache = []; + var utils = SpecialPowers.getDOMWindowUtils(window); + +@@ -184,25 +186,6 @@ function getUsage(usageHandler) + idbManager.getUsageForURI(uri, callback); + } + +-function getUsageSync() +-{ +- let usage; +- +- getUsage(function(aUsage, aFileUsage) { +- usage = aUsage; +- }); +- +- let comp = SpecialPowers.wrap(Components); +- let thread = comp.classes["@mozilla.org/thread-manager;1"] +- .getService(comp.interfaces.nsIThreadManager) +- .currentThread; +- while (!usage) { +- thread.processNextEvent(true); +- } +- +- return usage; +-} +- + function scheduleGC() + { + SpecialPowers.exactGC(window, continueToNextStep); +diff --git dom/indexedDB/test/test_file_quota.html dom/indexedDB/test/test_file_quota.html +index b07880d..9fbc0c0 100644 +--- mozilla/dom/indexedDB/test/test_file_quota.html ++++ mozilla/dom/indexedDB/test/test_file_quota.html +@@ -13,14 +13,12 @@ + function testSteps() + { + const READ_WRITE = IDBTransaction.READ_WRITE; +- const DEFAULT_QUOTA_MB = 50; + + const name = window.location.pathname; + + const objectStoreName = "Blobs"; + +- const testData = { key: 0, value: {} }; +- const fileData = { key: 1, file: null }; ++ const fileData = { key: 1, file: getNullFile("random.bin", DEFAULT_QUOTA) }; + + let request = indexedDB.open(name, 1); + request.onerror = errorHandler; +@@ -32,21 +30,17 @@ + + let db = event.target.result; + +- let objectStore = db.createObjectStore(objectStoreName, { }); +- objectStore.add(testData.value, testData.key); +- +- let size = (DEFAULT_QUOTA_MB + 1) * 1024 * 1024 - getUsageSync(); +- fileData.file = getNullFile("random.bin", size); ++ db.createObjectStore(objectStoreName, { }); + + event = yield; + + is(event.type, "success", "Got correct event type"); + + trans = db.transaction([objectStoreName], READ_WRITE); +- objectStore = trans.objectStore(objectStoreName); ++ let objectStore = trans.objectStore(objectStoreName); + + request = objectStore.add(fileData.file, fileData.key); +- request.addEventListener("error", new ExpectError("UnknownError")); ++ request.addEventListener("error", new ExpectError("UnknownError", true)); + request.onsuccess = unexpectedSuccessHandler; + event = yield; + +diff --git dom/indexedDB/test/test_filehandle_quota.html dom/indexedDB/test/test_filehandle_quota.html +index addaf01..0506279 100644 +--- mozilla/dom/indexedDB/test/test_filehandle_quota.html ++++ mozilla/dom/indexedDB/test/test_filehandle_quota.html +@@ -13,7 +13,6 @@ + function testSteps() + { + const READ_WRITE = IDBTransaction.READ_WRITE; +- const DEFAULT_QUOTA_MB = 50; + + const name = window.location.pathname; + +@@ -39,10 +38,10 @@ + + let lockedFile = fileHandle.open("readwrite"); + +- let blob = getNullBlob((50 + 1) * 1024 * 1024 - getUsageSync()); ++ let blob = getNullBlob(DEFAULT_QUOTA); + + request = lockedFile.write(blob); +- request.addEventListener("error", new ExpectError("UnknownError")); ++ request.addEventListener("error", new ExpectError("UnknownError", true)); + request.onsuccess = unexpectedSuccessHandler; + event = yield; + +diff --git dom/quota/FileStreams.cpp dom/quota/FileStreams.cpp +new file mode 100644 +index 0000000..9de244f +--- /dev/null ++++ mozilla/dom/quota/FileStreams.cpp +@@ -0,0 +1,123 @@ ++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* vim: set ts=2 et sw=2 tw=80: */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#include "FileStreams.h" ++ ++USING_QUOTA_NAMESPACE ++ ++template <class FileStreamBase> ++NS_IMETHODIMP ++FileQuotaStream<FileStreamBase>::SetEOF() ++{ ++ nsresult rv = FileStreamBase::SetEOF(); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ if (mQuotaObject) { ++ int64_t offset; ++ nsresult rv = FileStreamBase::Tell(&offset); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ mQuotaObject->UpdateSize(offset); ++ } ++ ++ return NS_OK; ++} ++ ++template <class FileStreamBase> ++NS_IMETHODIMP ++FileQuotaStream<FileStreamBase>::Close() ++{ ++ nsresult rv = FileStreamBase::Close(); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ mQuotaObject = nullptr; ++ ++ return NS_OK; ++} ++ ++template <class FileStreamBase> ++nsresult ++FileQuotaStream<FileStreamBase>::DoOpen() ++{ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ NS_ASSERTION(!mQuotaObject, "Creating quota object more than once?"); ++ mQuotaObject = quotaManager->GetQuotaObject(mOrigin, ++ FileStreamBase::mOpenParams.localFile); ++ ++ nsresult rv = FileStreamBase::DoOpen(); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ if (mQuotaObject && (FileStreamBase::mOpenParams.ioFlags & PR_TRUNCATE)) { ++ mQuotaObject->UpdateSize(0); ++ } ++ ++ return NS_OK; ++} ++ ++template <class FileStreamBase> ++NS_IMETHODIMP ++FileQuotaStreamWithWrite<FileStreamBase>::Write(const char* aBuf, ++ uint32_t aCount, ++ uint32_t* _retval) ++{ ++ nsresult rv; ++ ++ if (FileQuotaStreamWithWrite::mQuotaObject) { ++ int64_t offset; ++ rv = FileStreamBase::Tell(&offset); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ if (!FileQuotaStreamWithWrite:: ++ mQuotaObject->MaybeAllocateMoreSpace(offset, aCount)) { ++ return NS_ERROR_FAILURE; ++ } ++ } ++ ++ rv = FileStreamBase::Write(aBuf, aCount, _retval); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ return NS_OK; ++} ++ ++NS_IMPL_ISUPPORTS_INHERITED0(FileInputStream, nsFileInputStream) ++ ++already_AddRefed<FileInputStream> ++FileInputStream::Create(const nsACString& aOrigin, nsIFile* aFile, ++ int32_t aIOFlags, int32_t aPerm, ++ int32_t aBehaviorFlags) ++{ ++ nsRefPtr<FileInputStream> stream = new FileInputStream(aOrigin); ++ nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ return stream.forget(); ++} ++ ++NS_IMPL_ISUPPORTS_INHERITED0(FileOutputStream, nsFileOutputStream) ++ ++already_AddRefed<FileOutputStream> ++FileOutputStream::Create(const nsACString& aOrigin, nsIFile* aFile, ++ int32_t aIOFlags, int32_t aPerm, ++ int32_t aBehaviorFlags) ++{ ++ nsRefPtr<FileOutputStream> stream = new FileOutputStream(aOrigin); ++ nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ return stream.forget(); ++} ++ ++NS_IMPL_ISUPPORTS_INHERITED0(FileStream, nsFileStream) ++ ++already_AddRefed<FileStream> ++FileStream::Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags, ++ int32_t aPerm, int32_t aBehaviorFlags) ++{ ++ nsRefPtr<FileStream> stream = new FileStream(aOrigin); ++ nsresult rv = stream->Init(aFile, aIOFlags, aPerm, aBehaviorFlags); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ return stream.forget(); ++} +diff --git dom/quota/FileStreams.h dom/quota/FileStreams.h +new file mode 100644 +index 0000000..77bfad4 +--- /dev/null ++++ mozilla/dom/quota/FileStreams.h +@@ -0,0 +1,115 @@ ++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* vim: set ts=2 et sw=2 tw=80: */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#ifndef mozilla_dom_quota_filestreams_h__ ++#define mozilla_dom_quota_filestreams_h__ ++ ++#include "QuotaCommon.h" ++ ++#include "nsFileStreams.h" ++ ++#include "QuotaManager.h" ++ ++BEGIN_QUOTA_NAMESPACE ++ ++template <class FileStreamBase> ++class FileQuotaStream : public FileStreamBase ++{ ++public: ++ // nsFileStreamBase override ++ NS_IMETHOD ++ SetEOF() MOZ_OVERRIDE; ++ ++ NS_IMETHOD ++ Close() MOZ_OVERRIDE; ++ ++protected: ++ FileQuotaStream(const nsACString& aOrigin) ++ : mOrigin(aOrigin) ++ { } ++ ++ // nsFileStreamBase override ++ virtual nsresult ++ DoOpen() MOZ_OVERRIDE; ++ ++ nsCString mOrigin; ++ nsRefPtr<QuotaObject> mQuotaObject; ++}; ++ ++template <class FileStreamBase> ++class FileQuotaStreamWithWrite : public FileQuotaStream<FileStreamBase> ++{ ++public: ++ // nsFileStreamBase override ++ NS_IMETHOD ++ Write(const char* aBuf, uint32_t aCount, uint32_t* _retval) MOZ_OVERRIDE; ++ ++protected: ++ FileQuotaStreamWithWrite(const nsACString& aOrigin) ++ : FileQuotaStream<FileStreamBase>(aOrigin) ++ { } ++}; ++ ++class FileInputStream : public FileQuotaStream<nsFileInputStream> ++{ ++public: ++ NS_DECL_ISUPPORTS_INHERITED ++ ++ static already_AddRefed<FileInputStream> ++ Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1, ++ int32_t aPerm = -1, int32_t aBehaviorFlags = 0); ++ ++private: ++ FileInputStream(const nsACString& aOrigin) ++ : FileQuotaStream<nsFileInputStream>(aOrigin) ++ { } ++ ++ virtual ~FileInputStream() { ++ Close(); ++ } ++}; ++ ++class FileOutputStream : public FileQuotaStreamWithWrite<nsFileOutputStream> ++{ ++public: ++ NS_DECL_ISUPPORTS_INHERITED ++ ++ static already_AddRefed<FileOutputStream> ++ Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1, ++ int32_t aPerm = -1, int32_t aBehaviorFlags = 0); ++ ++private: ++ FileOutputStream(const nsACString& aOrigin) ++ : FileQuotaStreamWithWrite<nsFileOutputStream>(aOrigin) ++ { } ++ ++ virtual ~FileOutputStream() { ++ Close(); ++ } ++}; ++ ++class FileStream : public FileQuotaStreamWithWrite<nsFileStream> ++{ ++public: ++ NS_DECL_ISUPPORTS_INHERITED ++ ++ static already_AddRefed<FileStream> ++ Create(const nsACString& aOrigin, nsIFile* aFile, int32_t aIOFlags = -1, ++ int32_t aPerm = -1, int32_t aBehaviorFlags = 0); ++ ++private: ++ FileStream(const nsACString& aOrigin) ++ : FileQuotaStreamWithWrite<nsFileStream>(aOrigin) ++ { } ++ ++ virtual ~FileStream() { ++ Close(); ++ } ++}; ++ ++END_QUOTA_NAMESPACE ++ ++#endif /* mozilla_dom_quota_filestreams_h__ */ +diff --git dom/quota/Makefile.in dom/quota/Makefile.in +new file mode 100644 +index 0000000..49be551 +--- /dev/null ++++ mozilla/dom/quota/Makefile.in +@@ -0,0 +1,33 @@ ++# This Source Code Form is subject to the terms of the Mozilla Public ++# License, v. 2.0. If a copy of the MPL was not distributed with this file, ++# You can obtain one at http://mozilla.org/MPL/2.0/. ++ ++DEPTH = ../.. ++topsrcdir = @top_srcdir@ ++srcdir = @srcdir@ ++VPATH = @srcdir@ ++ ++include $(DEPTH)/config/autoconf.mk ++ ++MODULE = dom ++LIBRARY_NAME = domquota_s ++XPIDL_MODULE = dom_quota ++LIBXUL_LIBRARY = 1 ++FORCE_STATIC_LIB = 1 ++ ++include $(topsrcdir)/dom/dom-config.mk ++ ++EXPORTS_NAMESPACES = mozilla/dom/quota ++ ++CPPSRCS = \ ++ FileStreams.cpp \ ++ QuotaManager.cpp \ ++ $(NULL) ++ ++EXPORTS_mozilla/dom/quota = \ ++ FileStreams.h \ ++ QuotaCommon.h \ ++ QuotaManager.h \ ++ $(NULL) ++ ++include $(topsrcdir)/config/rules.mk +diff --git dom/quota/QuotaCommon.h dom/quota/QuotaCommon.h +new file mode 100644 +index 0000000..a415d17 +--- /dev/null ++++ mozilla/dom/quota/QuotaCommon.h +@@ -0,0 +1,23 @@ ++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* vim: set ts=2 et sw=2 tw=80: */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this file, ++ * You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#ifndef mozilla_dom_quota_quotacommon_h__ ++#define mozilla_dom_quota_quotacommon_h__ ++ ++#include "nsAutoPtr.h" ++#include "nsCOMPtr.h" ++#include "nsDebug.h" ++#include "nsStringGlue.h" ++#include "nsTArray.h" ++ ++#define BEGIN_QUOTA_NAMESPACE \ ++ namespace mozilla { namespace dom { namespace quota { ++#define END_QUOTA_NAMESPACE \ ++ } /* namespace quota */ } /* namespace dom */ } /* namespace mozilla */ ++#define USING_QUOTA_NAMESPACE \ ++ using namespace mozilla::dom::quota; ++ ++#endif // mozilla_dom_quota_quotacommon_h__ +diff --git dom/quota/QuotaManager.cpp dom/quota/QuotaManager.cpp +new file mode 100644 +index 0000000..b251606 +--- /dev/null ++++ mozilla/dom/quota/QuotaManager.cpp +@@ -0,0 +1,294 @@ ++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* vim: set ts=2 et sw=2 tw=80: */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this file, ++ * You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#include "QuotaManager.h" ++ ++#include "nsIFile.h" ++ ++#include "mozilla/ClearOnShutdown.h" ++#include "nsComponentManagerUtils.h" ++ ++#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h" ++ ++USING_QUOTA_NAMESPACE ++ ++namespace { ++ ++nsAutoPtr<QuotaManager> gInstance; ++ ++PLDHashOperator ++RemoveQuotaForPatternCallback(const nsACString& aKey, ++ nsRefPtr<OriginInfo>& aValue, ++ void* aUserArg) ++{ ++ NS_ASSERTION(!aKey.IsEmpty(), "Empty key!"); ++ NS_ASSERTION(aValue, "Null pointer!"); ++ NS_ASSERTION(aUserArg, "Null pointer!"); ++ ++ const nsACString* pattern = ++ static_cast<const nsACString*>(aUserArg); ++ ++ if (StringBeginsWith(aKey, *pattern)) { ++ return PL_DHASH_REMOVE; ++ } ++ ++ return PL_DHASH_NEXT; ++} ++ ++} // anonymous namespace ++ ++void ++QuotaObject::AddRef() ++{ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ if (!quotaManager) { ++ NS_ERROR("Null quota manager, this shouldn't happen, possible leak!"); ++ ++ NS_AtomicIncrementRefcnt(mRefCnt); ++ ++ return; ++ } ++ ++ MutexAutoLock lock(quotaManager->mQuotaMutex); ++ ++ ++mRefCnt; ++} ++ ++void ++QuotaObject::Release() ++{ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ if (!quotaManager) { ++ NS_ERROR("Null quota manager, this shouldn't happen, possible leak!"); ++ ++ nsrefcnt count = NS_AtomicDecrementRefcnt(mRefCnt); ++ if (count == 0) { ++ mRefCnt = 1; ++ delete this; ++ } ++ ++ return; ++ } ++ ++ { ++ MutexAutoLock lock(quotaManager->mQuotaMutex); ++ ++ --mRefCnt; ++ ++ if (mRefCnt > 0) { ++ return; ++ } ++ ++ if (mOriginInfo) { ++ mOriginInfo->mQuotaObjects.Remove(mPath); ++ } ++ } ++ ++ delete this; ++} ++ ++void ++QuotaObject::UpdateSize(int64_t aSize) ++{ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ MutexAutoLock lock(quotaManager->mQuotaMutex); ++ ++ if (mOriginInfo) { ++ mOriginInfo->mUsage -= mSize; ++ mSize = aSize; ++ mOriginInfo->mUsage += mSize; ++ } ++} ++ ++bool ++QuotaObject::MaybeAllocateMoreSpace(int64_t aOffset, int32_t aCount) ++{ ++ int64_t end = aOffset + aCount; ++ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ MutexAutoLock lock(quotaManager->mQuotaMutex); ++ ++ if (mSize >= end || !mOriginInfo) { ++ return true; ++ } ++ ++ int64_t newUsage = mOriginInfo->mUsage - mSize + end; ++ if (newUsage > mOriginInfo->mLimit) { ++ if (!indexedDB::IndexedDatabaseManager::QuotaIsLifted()) { ++ return false; ++ } ++ ++ nsCString origin = mOriginInfo->mOrigin; ++ ++ mOriginInfo->LockedClearOriginInfos(); ++ NS_ASSERTION(!mOriginInfo, ++ "Should have cleared in LockedClearOriginInfos!"); ++ ++ quotaManager->mOriginInfos.Remove(origin); ++ ++ mSize = end; ++ ++ return true; ++ } ++ ++ mOriginInfo->mUsage = newUsage; ++ mSize = end; ++ ++ return true; ++} ++ ++#ifdef DEBUG ++void ++OriginInfo::LockedClearOriginInfos() ++{ ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ NS_ASSERTION(quotaManager, "Shouldn't be null!"); ++ ++ quotaManager->mQuotaMutex.AssertCurrentThreadOwns(); ++ ++ mQuotaObjects.EnumerateRead(ClearOriginInfoCallback, nullptr); ++} ++#endif ++ ++// static ++PLDHashOperator ++OriginInfo::ClearOriginInfoCallback(const nsAString& aKey, ++ QuotaObject* aValue, ++ void* aUserArg) ++{ ++ NS_ASSERTION(!aKey.IsEmpty(), "Empty key!"); ++ NS_ASSERTION(aValue, "Null pointer!"); ++ ++ aValue->mOriginInfo = nullptr; ++ ++ return PL_DHASH_NEXT; ++} ++ ++// static ++QuotaManager* ++QuotaManager::GetOrCreate() ++{ ++ if (!gInstance) { ++ NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); ++ ++ gInstance = new QuotaManager(); ++ ++ ClearOnShutdown(&gInstance); ++ } ++ ++ return gInstance; ++} ++ ++// static ++QuotaManager* ++QuotaManager::Get() ++{ ++ // Does not return an owning reference. ++ return gInstance; ++} ++ ++void ++QuotaManager::InitQuotaForOrigin(const nsACString& aOrigin, ++ int64_t aLimit, ++ int64_t aUsage) ++{ ++ OriginInfo* info = new OriginInfo(aOrigin, aLimit * 1024 * 1024, aUsage); ++ ++ MutexAutoLock lock(mQuotaMutex); ++ ++ NS_ASSERTION(!mOriginInfos.GetWeak(aOrigin), "Replacing an existing entry!"); ++ mOriginInfos.Put(aOrigin, info); ++} ++ ++void ++QuotaManager::DecreaseUsageForOrigin(const nsACString& aOrigin, ++ int64_t aSize) ++{ ++ MutexAutoLock lock(mQuotaMutex); ++ ++ nsRefPtr<OriginInfo> originInfo; ++ mOriginInfos.Get(aOrigin, getter_AddRefs(originInfo)); ++ ++ if (originInfo) { ++ originInfo->mUsage -= aSize; ++ } ++} ++ ++void ++QuotaManager::RemoveQuotaForPattern(const nsACString& aPattern) ++{ ++ NS_ASSERTION(!aPattern.IsEmpty(), "Empty pattern!"); ++ ++ MutexAutoLock lock(mQuotaMutex); ++ ++ mOriginInfos.Enumerate(RemoveQuotaForPatternCallback, ++ const_cast<nsACString*>(&aPattern)); ++} ++ ++already_AddRefed<QuotaObject> ++QuotaManager::GetQuotaObject(const nsACString& aOrigin, ++ nsIFile* aFile) ++{ ++ NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); ++ ++ nsString path; ++ nsresult rv = aFile->GetPath(path); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ ++ int64_t fileSize; ++ ++ bool exists; ++ rv = aFile->Exists(&exists); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ ++ if (exists) { ++ rv = aFile->GetFileSize(&fileSize); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ } ++ else { ++ fileSize = 0; ++ } ++ ++ QuotaObject* info = nullptr; ++ { ++ MutexAutoLock lock(mQuotaMutex); ++ ++ nsRefPtr<OriginInfo> originInfo; ++ mOriginInfos.Get(aOrigin, getter_AddRefs(originInfo)); ++ ++ if (!originInfo) { ++ return nullptr; ++ } ++ ++ originInfo->mQuotaObjects.Get(path, &info); ++ ++ if (!info) { ++ info = new QuotaObject(originInfo, path, fileSize); ++ originInfo->mQuotaObjects.Put(path, info); ++ } ++ } ++ ++ nsRefPtr<QuotaObject> result = info; ++ return result.forget(); ++} ++ ++already_AddRefed<QuotaObject> ++QuotaManager::GetQuotaObject(const nsACString& aOrigin, ++ const nsAString& aPath) ++{ ++ nsresult rv; ++ nsCOMPtr<nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ ++ rv = file->InitWithPath(aPath); ++ NS_ENSURE_SUCCESS(rv, nullptr); ++ ++ return GetQuotaObject(aOrigin, file); ++} +diff --git dom/quota/QuotaManager.h dom/quota/QuotaManager.h +new file mode 100644 +index 0000000..e19acdd +--- /dev/null ++++ mozilla/dom/quota/QuotaManager.h +@@ -0,0 +1,147 @@ ++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* vim: set ts=2 et sw=2 tw=80: */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this file, ++ * You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#ifndef mozilla_dom_quota_quotamanager_h__ ++#define mozilla_dom_quota_quotamanager_h__ ++ ++#include "QuotaCommon.h" ++ ++#include "mozilla/Mutex.h" ++#include "nsDataHashtable.h" ++#include "nsRefPtrHashtable.h" ++#include "nsThreadUtils.h" ++ ++BEGIN_QUOTA_NAMESPACE ++ ++class OriginInfo; ++class QuotaManager; ++ ++class QuotaObject ++{ ++ friend class OriginInfo; ++ friend class QuotaManager; ++ ++public: ++ void ++ AddRef(); ++ ++ void ++ Release(); ++ ++ void ++ UpdateSize(int64_t aSize); ++ ++ bool ++ MaybeAllocateMoreSpace(int64_t aOffset, int32_t aCount); ++ ++private: ++ QuotaObject(OriginInfo* aOriginInfo, const nsAString& aPath, int64_t aSize) ++ : mOriginInfo(aOriginInfo), mPath(aPath), mSize(aSize) ++ { } ++ ++ virtual ~QuotaObject() ++ { } ++ ++ nsAutoRefCnt mRefCnt; ++ ++ OriginInfo* mOriginInfo; ++ nsString mPath; ++ int64_t mSize; ++}; ++ ++class OriginInfo ++{ ++ friend class QuotaManager; ++ friend class QuotaObject; ++ ++public: ++ OriginInfo(const nsACString& aOrigin, int64_t aLimit, int64_t aUsage) ++ : mOrigin(aOrigin), mLimit(aLimit), mUsage(aUsage) ++ { ++ mQuotaObjects.Init(); ++ } ++ ++ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OriginInfo) ++ ++private: ++ void ++#ifdef DEBUG ++ LockedClearOriginInfos(); ++#else ++ LockedClearOriginInfos() ++ { ++ mQuotaObjects.EnumerateRead(ClearOriginInfoCallback, nullptr); ++ } ++#endif ++ ++ static PLDHashOperator ++ ClearOriginInfoCallback(const nsAString& aKey, ++ QuotaObject* aValue, void* aUserArg); ++ ++ nsDataHashtable<nsStringHashKey, QuotaObject*> mQuotaObjects; ++ ++ nsCString mOrigin; ++ int64_t mLimit; ++ int64_t mUsage; ++}; ++ ++class QuotaManager ++{ ++ friend class nsAutoPtr<QuotaManager>; ++ friend class OriginInfo; ++ friend class QuotaObject; ++ ++public: ++ // Returns a non-owning reference. ++ static QuotaManager* ++ GetOrCreate(); ++ ++ // Returns a non-owning reference. ++ static QuotaManager* ++ Get(); ++ ++ void ++ InitQuotaForOrigin(const nsACString& aOrigin, ++ int64_t aLimit, ++ int64_t aUsage); ++ ++ void ++ DecreaseUsageForOrigin(const nsACString& aOrigin, ++ int64_t aSize); ++ ++ void ++ RemoveQuotaForPattern(const nsACString& aPattern); ++ ++ already_AddRefed<QuotaObject> ++ GetQuotaObject(const nsACString& aOrigin, ++ nsIFile* aFile); ++ ++ already_AddRefed<QuotaObject> ++ GetQuotaObject(const nsACString& aOrigin, ++ const nsAString& aPath); ++ ++private: ++ QuotaManager() ++ : mQuotaMutex("QuotaManager.mQuotaMutex") ++ { ++ NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); ++ ++ mOriginInfos.Init(); ++ } ++ ++ virtual ~QuotaManager() ++ { ++ NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); ++ } ++ ++ mozilla::Mutex mQuotaMutex; ++ ++ nsRefPtrHashtable<nsCStringHashKey, OriginInfo> mOriginInfos; ++}; ++ ++END_QUOTA_NAMESPACE ++ ++#endif /* mozilla_dom_quota_quotamanager_h__ */ +diff --git layout/build/Makefile.in layout/build/Makefile.in +index e6b32da..496b55f 100644 +--- mozilla/layout/build/Makefile.in ++++ mozilla/layout/build/Makefile.in +@@ -69,6 +69,7 @@ SHARED_LIBRARY_LIBS = \ + $(DEPTH)/dom/encoding/$(LIB_PREFIX)domencoding_s.$(LIB_SUFFIX) \ + $(DEPTH)/dom/file/$(LIB_PREFIX)domfile_s.$(LIB_SUFFIX) \ + $(DEPTH)/dom/power/$(LIB_PREFIX)dom_power_s.$(LIB_SUFFIX) \ ++ $(DEPTH)/dom/quota/$(LIB_PREFIX)domquota_s.$(LIB_SUFFIX) \ + $(DEPTH)/dom/settings/$(LIB_PREFIX)jsdomsettings_s.$(LIB_SUFFIX) \ + $(DEPTH)/dom/permission/$(LIB_PREFIX)jsdompermissionsettings_s.$(LIB_SUFFIX) \ + $(DEPTH)/dom/network/src/$(LIB_PREFIX)dom_network_s.$(LIB_SUFFIX) \ +diff --git netwerk/base/src/Makefile.in netwerk/base/src/Makefile.in +index 0c0d60e..e8cef48 100644 +--- mozilla/netwerk/base/src/Makefile.in ++++ mozilla/netwerk/base/src/Makefile.in +@@ -19,6 +19,7 @@ LIBXUL_LIBRARY = 1 + EXPORTS = \ + nsMIMEInputStream.h \ + nsURLHelper.h \ ++ nsFileStreams.h \ + $(NULL) + + EXPORTS_NAMESPACES = mozilla/net +diff --git netwerk/base/src/nsFileStreams.cpp netwerk/base/src/nsFileStreams.cpp +index 2420ffc..ecc26aa 100644 +--- mozilla/netwerk/base/src/nsFileStreams.cpp ++++ mozilla/netwerk/base/src/nsFileStreams.cpp +@@ -51,7 +51,9 @@ nsFileStreamBase::~nsFileStreamBase() + Close(); + } + +-NS_IMPL_THREADSAFE_ISUPPORTS1(nsFileStreamBase, nsISeekableStream) ++NS_IMPL_THREADSAFE_ISUPPORTS2(nsFileStreamBase, ++ nsISeekableStream, ++ nsIFileMetadata) + + NS_IMETHODIMP + nsFileStreamBase::Seek(int32_t whence, int64_t offset) +@@ -124,6 +126,52 @@ nsFileStreamBase::SetEOF() + return NS_OK; + } + ++NS_IMETHODIMP ++nsFileStreamBase::GetSize(int64_t* _retval) ++{ ++ nsresult rv = DoPendingOpen(); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ if (!mFD) { ++ return NS_BASE_STREAM_CLOSED; ++ } ++ ++ PRFileInfo64 info; ++ if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) { ++ return NS_BASE_STREAM_OSERROR; ++ } ++ ++ *_retval = int64_t(info.size); ++ ++ return NS_OK; ++} ++ ++NS_IMETHODIMP ++nsFileStreamBase::GetLastModified(int64_t* _retval) ++{ ++ nsresult rv = DoPendingOpen(); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ if (!mFD) { ++ return NS_BASE_STREAM_CLOSED; ++ } ++ ++ PRFileInfo64 info; ++ if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) { ++ return NS_BASE_STREAM_OSERROR; ++ } ++ ++ int64_t modTime = int64_t(info.modifyTime); ++ if (modTime == 0) { ++ *_retval = 0; ++ } ++ else { ++ *_retval = modTime / int64_t(PR_USEC_PER_MSEC); ++ } ++ ++ return NS_OK; ++} ++ + nsresult + nsFileStreamBase::Close() + { +@@ -934,13 +982,12 @@ nsSafeFileOutputStream::Write(const char *buf, uint32_t count, uint32_t *result) + //////////////////////////////////////////////////////////////////////////////// + // nsFileStream + +-NS_IMPL_ISUPPORTS_INHERITED4(nsFileStream, ++NS_IMPL_ISUPPORTS_INHERITED3(nsFileStream, + nsFileStreamBase, + nsIInputStream, + nsIOutputStream, +- nsIFileStream, +- nsIFileMetadata) +- ++ nsIFileStream) ++ + NS_IMETHODIMP + nsFileStream::Init(nsIFile* file, int32_t ioFlags, int32_t perm, + int32_t behaviorFlags) +@@ -959,50 +1006,4 @@ nsFileStream::Init(nsIFile* file, int32_t ioFlags, int32_t perm, + mBehaviorFlags & nsIFileStream::DEFER_OPEN); + } + +-NS_IMETHODIMP +-nsFileStream::GetSize(int64_t* _retval) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mFD) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- PRFileInfo64 info; +- if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) { +- return NS_BASE_STREAM_OSERROR; +- } +- +- *_retval = int64_t(info.size); +- +- return NS_OK; +-} +- +-NS_IMETHODIMP +-nsFileStream::GetLastModified(int64_t* _retval) +-{ +- nsresult rv = DoPendingOpen(); +- NS_ENSURE_SUCCESS(rv, rv); +- +- if (!mFD) { +- return NS_BASE_STREAM_CLOSED; +- } +- +- PRFileInfo64 info; +- if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) { +- return NS_BASE_STREAM_OSERROR; +- } +- +- int64_t modTime = int64_t(info.modifyTime); +- if (modTime == 0) { +- *_retval = 0; +- } +- else { +- *_retval = modTime / int64_t(PR_USEC_PER_MSEC); +- } +- +- return NS_OK; +-} +- + //////////////////////////////////////////////////////////////////////////////// +diff --git netwerk/base/src/nsFileStreams.h netwerk/base/src/nsFileStreams.h +index 13e5b45..1aa6a82 100644 +--- mozilla/netwerk/base/src/nsFileStreams.h ++++ mozilla/netwerk/base/src/nsFileStreams.h +@@ -24,11 +24,13 @@ + + //////////////////////////////////////////////////////////////////////////////// + +-class nsFileStreamBase : public nsISeekableStream ++class nsFileStreamBase : public nsISeekableStream, ++ public nsIFileMetadata + { + public: + NS_DECL_ISUPPORTS + NS_DECL_NSISEEKABLESTREAM ++ NS_DECL_NSIFILEMETADATA + + nsFileStreamBase(); + virtual ~nsFileStreamBase(); +@@ -124,8 +126,8 @@ public: + NS_IMETHOD IsNonBlocking(bool* _retval) + { + return nsFileStreamBase::IsNonBlocking(_retval); +- } +- ++ } ++ + // Overrided from nsFileStreamBase + NS_IMETHOD Seek(int32_t aWhence, int64_t aOffset); + +@@ -260,13 +262,11 @@ protected: + class nsFileStream : public nsFileStreamBase, + public nsIInputStream, + public nsIOutputStream, +- public nsIFileStream, +- public nsIFileMetadata ++ public nsIFileStream + { + public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIFILESTREAM +- NS_DECL_NSIFILEMETADATA + NS_FORWARD_NSIINPUTSTREAM(nsFileStreamBase::) + + // Can't use NS_FORWARD_NSIOUTPUTSTREAM due to overlapping methods +diff --git storage/public/Makefile.in storage/public/Makefile.in +index c485d4e..c05e6f3 100644 +--- mozilla/storage/public/Makefile.in ++++ mozilla/storage/public/Makefile.in +@@ -36,7 +36,6 @@ XPIDLSRCS = \ + mozIStorageCompletionCallback.idl \ + mozIStorageBaseStatement.idl \ + mozIStorageAsyncStatement.idl \ +- mozIStorageServiceQuotaManagement.idl \ + mozIStorageVacuumParticipant.idl \ + $(NULL) + # SEE ABOVE NOTE! +diff --git storage/public/mozIStorageService.idl storage/public/mozIStorageService.idl +index 3087a11..483649b 100644 +--- mozilla/storage/public/mozIStorageService.idl ++++ mozilla/storage/public/mozIStorageService.idl +@@ -7,6 +7,7 @@ + + interface mozIStorageConnection; + interface nsIFile; ++interface nsIFileURL; + + /** + * The mozIStorageService interface is intended to be implemented by +@@ -15,7 +16,7 @@ interface nsIFile; + * + * This is the only way to open a database connection. + */ +-[scriptable, uuid(fe8e95cb-b377-4c8d-bccb-d9198c67542b)] ++[scriptable, uuid(12bfad34-cca3-40fb-8736-d8bf9db61a27)] + interface mozIStorageService : nsISupports { + /** + * Get a connection to a named special database storage. +@@ -106,6 +107,16 @@ interface mozIStorageService : nsISupports { + */ + mozIStorageConnection openUnsharedDatabase(in nsIFile aDatabaseFile); + ++ /** ++ * See openDatabase(). Exactly the same only initialized with a file URL. ++ * Custom parameters can be passed to SQLite and VFS implementations through ++ * the query part of the URL. ++ * ++ * @param aURL ++ * A nsIFileURL that represents the database that is to be opened. ++ */ ++ mozIStorageConnection openDatabaseWithFileURL(in nsIFileURL aFileURL); ++ + /* + * Utilities + */ +diff --git storage/public/mozIStorageServiceQuotaManagement.idl storage/public/mozIStorageServiceQuotaManagement.idl +deleted file mode 100644 +index ee5086b..0000000 +--- mozilla/storage/public/mozIStorageServiceQuotaManagement.idl ++++ /dev/null +@@ -1,99 +0,0 @@ +-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +-/* vim: set ts=2 et sw=2 tw=80: */ +-/* This Source Code Form is subject to the terms of the Mozilla Public +- * License, v. 2.0. If a copy of the MPL was not distributed with this +- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +- +-#include "nsISupports.idl" +- +-interface mozIStorageConnection; +-interface nsIFile; +- +-[scriptable, function, uuid(ae94f0a5-ebdf-48f4-9959-085e13235d8d)] +-interface mozIStorageQuotaCallback : nsISupports +-{ +- /** +- * Called when the file size quota for a group of databases is exceeded. +- * +- * @param aFilename +- * The filename of the database that has exceeded the quota. +- * +- * @param aCurrentSizeLimit +- * The current size (in bytes) of the quota. +- * +- * @param aCurrentTotalSize +- * The current size of all databases in the quota group. +- * +- * @param aUserData +- * Any additional data that was provided to the +- * setQuotaForFilenamePattern function. +- * +- * @returns A new quota size. A new quota of 0 will disable the quota callback +- * and any quota value less than aCurrentTotalSize will cause the +- * database operation to fail with NS_ERROR_FILE_NO_DEVICE_SPACE. +- */ +- long long quotaExceeded(in ACString aFilename, +- in long long aCurrentSizeLimit, +- in long long aCurrentTotalSize, +- in nsISupports aUserData); +-}; +- +-/** +- * This is a temporary interface that should eventually merge with +- * mozIStorageService. +- */ +-[scriptable, uuid(4d81faf5-fe01-428b-99b8-c94cba12fd72)] +-interface mozIStorageServiceQuotaManagement : nsISupports +-{ +- /** +- * See mozIStorageService.openDatabase. Exactly the same only with a custom +- * SQLite VFS. +- */ +- mozIStorageConnection openDatabaseWithVFS(in nsIFile aDatabaseFile, +- in ACString aVFSName); +- +- /** +- * Set a file size quota for a group of databases matching the given filename +- * pattern, optionally specifying a callback when the quota is exceeded. +- * +- * @param aPattern +- * A pattern to match filenames for inclusion in the quota system. May +- * contain the following special characters: +- * '*' Matches any sequence of zero or more characters. +- * '?' Matches exactly one character. +- * [...] Matches one character from the enclosed list of characters. +- * [^...] Matches one character not in the enclosed list. +- * +- * @param aSizeLimit +- * The size limit (in bytes) for the quota group. +- * +- * @param aCallback +- * A callback that will be used when the quota is exceeded. +- * +- * @param aUserData +- * Additional information to be passed to the callback. +- */ +- void setQuotaForFilenamePattern(in ACString aPattern, +- in long long aSizeLimit, +- in mozIStorageQuotaCallback aCallback, +- in nsISupports aUserData); +- +- /** +- * Adds, removes, or updates the file size information maintained by the quota +- * system for files not opened through openDatabaseWithVFS(). +- * +- * Use this function when you want files to be included in quota calculations +- * that are either a) not SQLite databases, or b) SQLite databases that have +- * not been opened. +- * +- * This function will have no effect on files that do not match an existing +- * quota pattern (set previously by setQuotaForFilenamePattern()). +- * +- * @param aFile +- * The file for which quota information should be updated. If the file +- * exists then its size information will be added or refreshed. If the +- * file does not exist then the file will be removed from tracking +- * under the quota system. +- */ +- void updateQuotaInformationForFile(in nsIFile aFile); +-}; +diff --git storage/public/storage.h storage/public/storage.h +index 8e571e2..08f39f3 100644 +--- mozilla/storage/public/storage.h ++++ mozilla/storage/public/storage.h +@@ -24,7 +24,6 @@ + #include "mozIStorageStatementCallback.h" + #include "mozIStorageBindingParamsArray.h" + #include "mozIStorageBindingParams.h" +-#include "mozIStorageServiceQuotaManagement.h" + #include "mozIStorageVacuumParticipant.h" + #include "mozIStorageCompletionCallback.h" + #include "mozIStorageAsyncStatement.h" +diff --git storage/src/TelemetryVFS.cpp storage/src/TelemetryVFS.cpp +index 60de5c4..e4fce09 100644 +--- mozilla/storage/src/TelemetryVFS.cpp ++++ mozilla/storage/src/TelemetryVFS.cpp +@@ -10,6 +10,7 @@ + #include "sqlite3.h" + #include "nsThreadUtils.h" + #include "mozilla/Util.h" ++#include "mozilla/dom/quota/QuotaManager.h" + + /** + * This preference is a workaround to allow users/sysadmins to identify +@@ -24,6 +25,7 @@ + namespace { + + using namespace mozilla; ++using namespace mozilla::dom::quota; + + struct Histograms { + const char *name; +@@ -82,9 +84,17 @@ private: + }; + + struct telemetry_file { +- sqlite3_file base; // Base class. Must be first +- Histograms *histograms; // histograms pertaining to this file +- sqlite3_file pReal[1]; // This contains the vfs that actually does work ++ // Base class. Must be first ++ sqlite3_file base; ++ ++ // histograms pertaining to this file ++ Histograms *histograms; ++ ++ // quota object for this file ++ nsRefPtr<QuotaObject> quotaObject; ++ ++ // This contains the vfs that actually does work ++ sqlite3_file pReal[1]; + }; + + /* +@@ -99,6 +109,7 @@ xClose(sqlite3_file *pFile) + if( rc==SQLITE_OK ){ + delete p->base.pMethods; + p->base.pMethods = NULL; ++ p->quotaObject = nullptr; + } + return rc; + } +@@ -126,6 +137,9 @@ int + xWrite(sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite_int64 iOfst) + { + telemetry_file *p = (telemetry_file *)pFile; ++ if (p->quotaObject && !p->quotaObject->MaybeAllocateMoreSpace(iOfst, iAmt)) { ++ return SQLITE_FULL; ++ } + IOThreadAutoTimer ioTimer(p->histograms->writeMS); + int rc; + rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst); +@@ -144,6 +158,9 @@ xTruncate(sqlite3_file *pFile, sqlite_int64 size) + int rc; + Telemetry::AutoTimer<Telemetry::MOZ_SQLITE_TRUNCATE_MS> timer; + rc = p->pReal->pMethods->xTruncate(p->pReal, size); ++ if (rc == SQLITE_OK && p->quotaObject) { ++ p->quotaObject->UpdateSize(size); ++ } + return rc; + } + +@@ -300,6 +317,18 @@ xOpen(sqlite3_vfs* vfs, const char *zName, sqlite3_file* pFile, + break; + } + p->histograms = h; ++ ++ const char* origin; ++ if ((flags & SQLITE_OPEN_URI) && ++ (origin = sqlite3_uri_parameter(zName, "origin"))) { ++ QuotaManager* quotaManager = QuotaManager::Get(); ++ MOZ_ASSERT(quotaManager); ++ ++ p->quotaObject = quotaManager->GetQuotaObject(nsDependentCString(origin), ++ NS_ConvertUTF8toUTF16(zName)); ++ ++ } ++ + rc = orig_vfs->xOpen(orig_vfs, zName, p->pReal, flags, pOutFlags); + if( rc != SQLITE_OK ) + return rc; +diff --git storage/src/mozStorageConnection.cpp storage/src/mozStorageConnection.cpp +index 3afd3e1b..430824a 100644 +--- mozilla/storage/src/mozStorageConnection.cpp ++++ mozilla/storage/src/mozStorageConnection.cpp +@@ -12,6 +12,7 @@ + #include "nsIMemoryReporter.h" + #include "nsThreadUtils.h" + #include "nsIFile.h" ++#include "nsIFileURL.h" + #include "mozilla/Telemetry.h" + #include "mozilla/Mutex.h" + #include "mozilla/CondVar.h" +@@ -471,34 +472,83 @@ Connection::getAsyncExecutionTarget() + } + + nsresult +-Connection::initialize(nsIFile *aDatabaseFile, +- const char* aVFSName) ++Connection::initialize() + { + NS_ASSERTION (!mDBConn, "Initialize called on already opened database!"); + SAMPLE_LABEL("storage", "Connection::initialize"); + +- int srv; +- nsresult rv; ++ // in memory database requested, sqlite uses a magic file name ++ int srv = ::sqlite3_open_v2(":memory:", &mDBConn, mFlags, NULL); ++ if (srv != SQLITE_OK) { ++ mDBConn = nullptr; ++ return convertResultCode(srv); ++ } ++ ++ return initializeInternal(nullptr); ++} ++ ++nsresult ++Connection::initialize(nsIFile *aDatabaseFile) ++{ ++ NS_ASSERTION (aDatabaseFile, "Passed null file!"); ++ NS_ASSERTION (!mDBConn, "Initialize called on already opened database!"); ++ SAMPLE_LABEL("storage", "Connection::initialize"); + + mDatabaseFile = aDatabaseFile; + +- if (aDatabaseFile) { +- nsAutoString path; +- rv = aDatabaseFile->GetPath(path); +- NS_ENSURE_SUCCESS(rv, rv); ++ nsAutoString path; ++ nsresult rv = aDatabaseFile->GetPath(path); ++ NS_ENSURE_SUCCESS(rv, rv); + +- srv = ::sqlite3_open_v2(NS_ConvertUTF16toUTF8(path).get(), &mDBConn, mFlags, +- aVFSName); +- } +- else { +- // in memory database requested, sqlite uses a magic file name +- srv = ::sqlite3_open_v2(":memory:", &mDBConn, mFlags, aVFSName); ++ int srv = ::sqlite3_open_v2(NS_ConvertUTF16toUTF8(path).get(), &mDBConn, ++ mFlags, NULL); ++ if (srv != SQLITE_OK) { ++ mDBConn = nullptr; ++ return convertResultCode(srv); + } ++ ++ rv = initializeInternal(aDatabaseFile); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ mDatabaseFile = aDatabaseFile; ++ ++ return NS_OK; ++} ++ ++nsresult ++Connection::initialize(nsIFileURL *aFileURL) ++{ ++ NS_ASSERTION (aFileURL, "Passed null file URL!"); ++ NS_ASSERTION (!mDBConn, "Initialize called on already opened database!"); ++ SAMPLE_LABEL("storage", "Connection::initialize"); ++ ++ nsCOMPtr<nsIFile> databaseFile; ++ nsresult rv = aFileURL->GetFile(getter_AddRefs(databaseFile)); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ nsAutoCString spec; ++ rv = aFileURL->GetSpec(spec); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ int srv = ::sqlite3_open_v2(spec.get(), &mDBConn, mFlags, NULL); + if (srv != SQLITE_OK) { + mDBConn = nullptr; + return convertResultCode(srv); + } + ++ rv = initializeInternal(databaseFile); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ mFileURL = aFileURL; ++ mDatabaseFile = databaseFile; ++ ++ return NS_OK; ++} ++ ++ ++nsresult ++Connection::initializeInternal(nsIFile* aDatabaseFile) ++{ + // Properly wrap the database handle's mutex. + sharedDBMutex.initWithMutex(sqlite3_db_mutex(mDBConn)); + +@@ -522,14 +572,14 @@ Connection::initialize(nsIFile *aDatabaseFile, + nsAutoCString pageSizeQuery(MOZ_STORAGE_UNIQUIFY_QUERY_STR + "PRAGMA page_size = "); + pageSizeQuery.AppendInt(pageSize); +- rv = ExecuteSimpleSQL(pageSizeQuery); ++ nsresult rv = ExecuteSimpleSQL(pageSizeQuery); + NS_ENSURE_SUCCESS(rv, rv); + + // Get the current page_size, since it may differ from the specified value. + sqlite3_stmt *stmt; + NS_NAMED_LITERAL_CSTRING(pragma_page_size, + MOZ_STORAGE_UNIQUIFY_QUERY_STR "PRAGMA page_size"); +- srv = prepareStatement(pragma_page_size, &stmt); ++ int srv = prepareStatement(pragma_page_size, &stmt); + if (srv == SQLITE_OK) { + if (SQLITE_ROW == stepStatement(stmt)) { + pageSize = ::sqlite3_column_int64(stmt, 0); +@@ -962,7 +1012,8 @@ Connection::Clone(bool aReadOnly, + nsRefPtr<Connection> clone = new Connection(mStorageService, flags); + NS_ENSURE_TRUE(clone, NS_ERROR_OUT_OF_MEMORY); + +- nsresult rv = clone->initialize(mDatabaseFile); ++ nsresult rv = mFileURL ? clone->initialize(mFileURL) ++ : clone->initialize(mDatabaseFile); + NS_ENSURE_SUCCESS(rv, rv); + + // Copy over pragmas from the original connection. +diff --git storage/src/mozStorageConnection.h storage/src/mozStorageConnection.h +index b71f5db..97f5cf8 100644 +--- mozilla/storage/src/mozStorageConnection.h ++++ mozilla/storage/src/mozStorageConnection.h +@@ -25,6 +25,7 @@ + + struct PRLock; + class nsIFile; ++class nsIFileURL; + class nsIEventTarget; + class nsIThread; + +@@ -63,18 +64,27 @@ public: + Connection(Service *aService, int aFlags); + + /** ++ * Creates the connection to an in-memory database. ++ */ ++ nsresult initialize(); ++ ++ /** + * Creates the connection to the database. + * + * @param aDatabaseFile + * The nsIFile of the location of the database to open, or create if it +- * does not exist. Passing in nullptr here creates an in-memory +- * database. +- * @param aVFSName +- * The VFS that SQLite will use when opening this database. NULL means +- * "default". ++ * does not exist. + */ +- nsresult initialize(nsIFile *aDatabaseFile, +- const char* aVFSName = NULL); ++ nsresult initialize(nsIFile *aDatabaseFile); ++ ++ /** ++ * Creates the connection to the database. ++ * ++ * @param aFileURL ++ * The nsIFileURL of the location of the database to open, or create if it ++ * does not exist. ++ */ ++ nsresult initialize(nsIFileURL *aFileURL); + + // fetch the native handle + sqlite3 *GetNativeConnection() { return mDBConn; } +@@ -155,6 +165,8 @@ public: + private: + ~Connection(); + ++ nsresult initializeInternal(nsIFile *aDatabaseFile); ++ + /** + * Sets the database into a closed state so no further actions can be + * performed. +@@ -206,6 +218,7 @@ private: + int progressHandler(); + + sqlite3 *mDBConn; ++ nsCOMPtr<nsIFileURL> mFileURL; + nsCOMPtr<nsIFile> mDatabaseFile; + + /** +diff --git storage/src/mozStorageService.cpp storage/src/mozStorageService.cpp +index 00661d6..862a7da 100644 +--- mozilla/storage/src/mozStorageService.cpp ++++ mozilla/storage/src/mozStorageService.cpp +@@ -24,8 +24,6 @@ + #include "mozilla/Preferences.h" + + #include "sqlite3.h" +-#include "test_quota.h" +-#include "test_quota.c" + + #ifdef SQLITE_OS_WIN + // "windows.h" was included and it can #define lots of things we care about... +@@ -35,61 +33,6 @@ + #include "nsIPromptService.h" + #include "nsIMemoryReporter.h" + +-namespace { +- +-class QuotaCallbackData +-{ +-public: +- QuotaCallbackData(mozIStorageQuotaCallback *aCallback, +- nsISupports *aUserData) +- : callback(aCallback), userData(aUserData) +- { +- MOZ_COUNT_CTOR(QuotaCallbackData); +- } +- +- ~QuotaCallbackData() +- { +- MOZ_COUNT_DTOR(QuotaCallbackData); +- } +- +- static void Callback(const char *zFilename, +- sqlite3_int64 *piLimit, +- sqlite3_int64 iSize, +- void *pArg) +- { +- NS_ASSERTION(zFilename && strlen(zFilename), "Null or empty filename!"); +- NS_ASSERTION(piLimit, "Null pointer!"); +- +- QuotaCallbackData *data = static_cast<QuotaCallbackData*>(pArg); +- if (!data) { +- // No callback specified, return immediately. +- return; +- } +- +- NS_ASSERTION(data->callback, "Should never have a null callback!"); +- +- nsDependentCString filename(zFilename); +- +- int64_t newLimit; +- if (NS_SUCCEEDED(data->callback->QuotaExceeded(filename, *piLimit, +- iSize, data->userData, +- &newLimit))) { +- *piLimit = newLimit; +- } +- } +- +- static void Destroy(void *aUserData) +- { +- delete static_cast<QuotaCallbackData*>(aUserData); +- } +- +-private: +- nsCOMPtr<mozIStorageQuotaCallback> callback; +- nsCOMPtr<nsISupports> userData; +-}; +- +-} // anonymous namespace +- + //////////////////////////////////////////////////////////////////////////////// + //// Defines + +@@ -345,11 +288,10 @@ private: + //////////////////////////////////////////////////////////////////////////////// + //// Service + +-NS_IMPL_THREADSAFE_ISUPPORTS3( ++NS_IMPL_THREADSAFE_ISUPPORTS2( + Service, + mozIStorageService, +- nsIObserver, +- mozIStorageServiceQuotaManagement ++ nsIObserver + ) + + Service *Service::gService = nullptr; +@@ -438,10 +380,6 @@ Service::~Service() + + // Shutdown the sqlite3 API. Warn if shutdown did not turn out okay, but + // there is nothing actionable we can do in that case. +- rc = ::sqlite3_quota_shutdown(); +- if (rc != SQLITE_OK) +- NS_WARNING("sqlite3 did not shutdown cleanly."); +- + rc = ::sqlite3_shutdown(); + if (rc != SQLITE_OK) + NS_WARNING("sqlite3 did not shutdown cleanly."); +@@ -636,9 +574,6 @@ Service::initialize() + } else { + NS_WARNING("Failed to register telemetry VFS"); + } +- rc = ::sqlite3_quota_initialize("telemetry-vfs", 0); +- if (rc != SQLITE_OK) +- return convertResultCode(rc); + + // Set the default value for the toolkit.storage.synchronous pref. It will be + // updated with the user preference on the main thread. +@@ -739,28 +674,24 @@ Service::OpenSpecialDatabase(const char *aStorageKey, + // connection to use a memory DB. + } + else if (::strcmp(aStorageKey, "profile") == 0) { +- + rv = NS_GetSpecialDirectory(NS_APP_STORAGE_50_FILE, + getter_AddRefs(storageFile)); + NS_ENSURE_SUCCESS(rv, rv); + +- nsString filename; +- storageFile->GetPath(filename); +- nsCString filename8 = NS_ConvertUTF16toUTF8(filename.get()); + // fall through to DB initialization + } + else { + return NS_ERROR_INVALID_ARG; + } + +- Connection *msc = new Connection(this, SQLITE_OPEN_READWRITE); +- NS_ENSURE_TRUE(msc, NS_ERROR_OUT_OF_MEMORY); ++ nsRefPtr<Connection> msc = new Connection(this, SQLITE_OPEN_READWRITE); + +- rv = msc->initialize(storageFile); ++ rv = storageFile ? msc->initialize(storageFile) : msc->initialize(); + NS_ENSURE_SUCCESS(rv, rv); + +- NS_ADDREF(*_connection = msc); ++ msc.forget(_connection); + return NS_OK; ++ + } + + NS_IMETHODIMP +@@ -774,12 +705,11 @@ Service::OpenDatabase(nsIFile *aDatabaseFile, + int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE | + SQLITE_OPEN_CREATE; + nsRefPtr<Connection> msc = new Connection(this, flags); +- NS_ENSURE_TRUE(msc, NS_ERROR_OUT_OF_MEMORY); + + nsresult rv = msc->initialize(aDatabaseFile); + NS_ENSURE_SUCCESS(rv, rv); + +- NS_ADDREF(*_connection = msc); ++ msc.forget(_connection); + return NS_OK; + } + +@@ -794,12 +724,30 @@ Service::OpenUnsharedDatabase(nsIFile *aDatabaseFile, + int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_PRIVATECACHE | + SQLITE_OPEN_CREATE; + nsRefPtr<Connection> msc = new Connection(this, flags); +- NS_ENSURE_TRUE(msc, NS_ERROR_OUT_OF_MEMORY); + + nsresult rv = msc->initialize(aDatabaseFile); + NS_ENSURE_SUCCESS(rv, rv); + +- NS_ADDREF(*_connection = msc); ++ msc.forget(_connection); ++ return NS_OK; ++} ++ ++NS_IMETHODIMP ++Service::OpenDatabaseWithFileURL(nsIFileURL *aFileURL, ++ mozIStorageConnection **_connection) ++{ ++ NS_ENSURE_ARG(aFileURL); ++ ++ // Always ensure that SQLITE_OPEN_CREATE is passed in for compatibility ++ // reasons. ++ int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE | ++ SQLITE_OPEN_CREATE | SQLITE_OPEN_URI; ++ nsRefPtr<Connection> msc = new Connection(this, flags); ++ ++ nsresult rv = msc->initialize(aFileURL); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ msc.forget(_connection); + return NS_OK; + } + +@@ -885,67 +833,5 @@ Service::Observe(nsISupports *, const char *aTopic, const PRUnichar *) + return NS_OK; + } + +-//////////////////////////////////////////////////////////////////////////////// +-//// mozIStorageServiceQuotaManagement +- +-NS_IMETHODIMP +-Service::OpenDatabaseWithVFS(nsIFile *aDatabaseFile, +- const nsACString &aVFSName, +- mozIStorageConnection **_connection) +-{ +- NS_ENSURE_ARG(aDatabaseFile); +- +- // Always ensure that SQLITE_OPEN_CREATE is passed in for compatibility +- // reasons. +- int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE | +- SQLITE_OPEN_CREATE; +- nsRefPtr<Connection> msc = new Connection(this, flags); +- NS_ENSURE_TRUE(msc, NS_ERROR_OUT_OF_MEMORY); +- +- nsresult rv = msc->initialize(aDatabaseFile, +- PromiseFlatCString(aVFSName).get()); +- NS_ENSURE_SUCCESS(rv, rv); +- +- NS_ADDREF(*_connection = msc); +- return NS_OK; +-} +- +-NS_IMETHODIMP +-Service::SetQuotaForFilenamePattern(const nsACString &aPattern, +- int64_t aSizeLimit, +- mozIStorageQuotaCallback *aCallback, +- nsISupports *aUserData) +-{ +- NS_ENSURE_FALSE(aPattern.IsEmpty(), NS_ERROR_INVALID_ARG); +- +- nsAutoPtr<QuotaCallbackData> data; +- if (aSizeLimit && aCallback) { +- data = new QuotaCallbackData(aCallback, aUserData); +- } +- +- int rc = ::sqlite3_quota_set(PromiseFlatCString(aPattern).get(), +- aSizeLimit, QuotaCallbackData::Callback, +- data, QuotaCallbackData::Destroy); +- NS_ENSURE_TRUE(rc == SQLITE_OK, convertResultCode(rc)); +- +- data.forget(); +- return NS_OK; +-} +- +-NS_IMETHODIMP +-Service::UpdateQuotaInformationForFile(nsIFile *aFile) +-{ +- NS_ENSURE_ARG_POINTER(aFile); +- +- nsString path; +- nsresult rv = aFile->GetPath(path); +- NS_ENSURE_SUCCESS(rv, rv); +- +- int rc = ::sqlite3_quota_file(NS_ConvertUTF16toUTF8(path).get()); +- NS_ENSURE_TRUE(rc == SQLITE_OK, convertResultCode(rc)); +- +- return NS_OK; +-} +- + } // namespace storage + } // namespace mozilla +diff --git storage/src/mozStorageService.h storage/src/mozStorageService.h +index 21c1ff8..3f5a546 100644 +--- mozilla/storage/src/mozStorageService.h ++++ mozilla/storage/src/mozStorageService.h +@@ -15,7 +15,6 @@ + #include "mozilla/Mutex.h" + + #include "mozIStorageService.h" +-#include "mozIStorageServiceQuotaManagement.h" + + class nsIMemoryReporter; + class nsIMemoryMultiReporter; +@@ -28,7 +27,6 @@ namespace storage { + class Connection; + class Service : public mozIStorageService + , public nsIObserver +- , public mozIStorageServiceQuotaManagement + { + public: + /** +@@ -58,7 +56,6 @@ public: + NS_DECL_ISUPPORTS + NS_DECL_MOZISTORAGESERVICE + NS_DECL_NSIOBSERVER +- NS_DECL_MOZISTORAGESERVICEQUOTAMANAGEMENT + + /** + * Obtains an already AddRefed pointer to XPConnect. This is used by +diff --git toolkit/toolkit-makefiles.sh toolkit/toolkit-makefiles.sh +index 6a7d714..8f1bbe0 100644 +--- mozilla/toolkit/toolkit-makefiles.sh ++++ mozilla/toolkit/toolkit-makefiles.sh +@@ -68,6 +68,7 @@ MAKEFILES_dom=" + dom/plugins/base/Makefile + dom/plugins/ipc/Makefile + dom/power/Makefile ++ dom/quota/Makefile + dom/settings/Makefile + dom/sms/Makefile + dom/sms/interfaces/Makefile
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201301021958.r02JwJ9p030209>