[SVN-Commit] r1130 - in trunk: Mk mail/thunderbird/files www/firefox/files www/seamonkey/files
svn-freebsd-gecko at chruetertee.ch
svn-freebsd-gecko at chruetertee.ch
Wed Jan 2 19:58:27 UTC 2013
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 at 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 at 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 at 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
More information about the freebsd-gecko
mailing list