Bug 787804 - Rewrite quota handling (eliminate test_quota.c). r=bent,asuth,vladan
authorJan Varga <jan.varga@gmail.com>
Mon, 17 Dec 2012 20:25:10 +0100
changeset 116302 6328b64258aeb42d066414861ccc0e389846f4ac
parent 116301 a09a149d8a44af3f18d84cdfcd2aacf7db42f7df
child 116303 249e7db380b0e4a2da0df37aa34844c364fd42ee
push id24045
push userryanvm@gmail.com
push dateTue, 18 Dec 2012 00:23:36 +0000
treeherdermozilla-central@2e70b718903a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent, asuth, vladan
bugs787804
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 787804 - Rewrite quota handling (eliminate test_quota.c). r=bent,asuth,vladan
db/sqlite3/README.MOZILLA
db/sqlite3/src/sqlite.def
db/sqlite3/src/test_quota.c
db/sqlite3/src/test_quota.h
dom/Makefile.in
dom/dom-config.mk
dom/file/FileStreamWrappers.cpp
dom/file/LockedFile.cpp
dom/file/nsIFileStorage.h
dom/indexedDB/FileManager.cpp
dom/indexedDB/FileManager.h
dom/indexedDB/FileStream.cpp
dom/indexedDB/FileStream.h
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/IDBFactory.h
dom/indexedDB/IDBFileHandle.cpp
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IDBTransaction.cpp
dom/indexedDB/IndexedDatabaseInlines.h
dom/indexedDB/IndexedDatabaseManager.cpp
dom/indexedDB/IndexedDatabaseManager.h
dom/indexedDB/Makefile.in
dom/indexedDB/OpenDatabaseHelper.cpp
dom/indexedDB/OpenDatabaseHelper.h
dom/indexedDB/nsIStandardFileStream.idl
dom/indexedDB/test/Makefile.in
dom/indexedDB/test/file.js
dom/indexedDB/test/test_file_quota.html
dom/indexedDB/test/test_filehandle_quota.html
dom/quota/FileStreams.cpp
dom/quota/FileStreams.h
dom/quota/Makefile.in
dom/quota/QuotaCommon.h
dom/quota/QuotaManager.cpp
dom/quota/QuotaManager.h
layout/build/Makefile.in
netwerk/base/src/Makefile.in
netwerk/base/src/nsFileStreams.cpp
netwerk/base/src/nsFileStreams.h
storage/public/Makefile.in
storage/public/mozIStorageService.idl
storage/public/mozIStorageServiceQuotaManagement.idl
storage/public/storage.h
storage/src/TelemetryVFS.cpp
storage/src/mozStorageConnection.cpp
storage/src/mozStorageConnection.h
storage/src/mozStorageService.cpp
storage/src/mozStorageService.h
toolkit/toolkit-makefiles.sh
--- a/db/sqlite3/README.MOZILLA
+++ b/db/sqlite3/README.MOZILLA
@@ -4,18 +4,18 @@ This is sqlite 3.7.14.1
 
 See http://www.sqlite.org/ for more info.
 
 We have a mozilla-specific Makefile.in in src/ (normally no
 Makefile.in there) that we use to build.
 
 To move to a new version:
 
-Copy the sqlite3.h and sqlite3.c files from the amalgamation of sqlite. Also,
-copy test_quota.h and test_quota.c from the full source package.
+Copy the sqlite3.h and sqlite3.c files from the amalgamation of sqlite.
+(We no longer use test_quota.h and test_quota.c)
 
 Be sure to update SQLITE_VERSION accordingly in $(topsrcdir)/configure.in as
 well as the version number at the top of this file.
 
 -- Paul O’Shannessy <paul@oshannessy.com>, 01/2011
 
 We are using an experimental quota management feature included in test_quota.c.
 This file is not compiled into mozsqlite, but instead included directly into
--- a/db/sqlite3/src/sqlite.def
+++ b/db/sqlite3/src/sqlite.def
@@ -127,16 +127,17 @@ EXPORTS
         sqlite3_stmt_readonly
         sqlite3_stmt_status
         sqlite3_thread_cleanup
         sqlite3_total_changes
         sqlite3_trace
         sqlite3_transfer_bindings
         sqlite3_unlock_notify
         sqlite3_update_hook
+        sqlite3_uri_parameter
         sqlite3_user_data
         sqlite3_value_blob
         sqlite3_value_bytes
         sqlite3_value_bytes16
         sqlite3_value_double
         sqlite3_value_int
         sqlite3_value_int64
         sqlite3_value_numeric_type
deleted file mode 100644
--- a/db/sqlite3/src/test_quota.c
+++ /dev/null
@@ -1,2001 +0,0 @@
-/*
-** 2010 September 31
-**
-** The author disclaims copyright to this source code.  In place of
-** a legal notice, here is a blessing:
-**
-**    May you do good and not evil.
-**    May you find forgiveness for yourself and forgive others.
-**    May you share freely, never taking more than you give.
-**
-*************************************************************************
-**
-** This file contains a VFS "shim" - a layer that sits in between the
-** pager and the real VFS.
-**
-** This particular shim enforces a quota system on files.  One or more
-** database files are in a "quota group" that is defined by a GLOB
-** pattern.  A quota is set for the combined size of all files in the
-** the group.  A quota of zero means "no limit".  If the total size
-** of all files in the quota group is greater than the limit, then
-** write requests that attempt to enlarge a file fail with SQLITE_FULL.
-**
-** However, before returning SQLITE_FULL, the write requests invoke
-** a callback function that is configurable for each quota group.
-** This callback has the opportunity to enlarge the quota.  If the
-** callback does enlarge the quota such that the total size of all
-** files within the group is less than the new quota, then the write
-** continues as if nothing had happened.
-*/
-#include "test_quota.h"
-#include <string.h>
-#include <assert.h>
-
-/*
-** For an build without mutexes, no-op the mutex calls.
-*/
-#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE==0
-#define sqlite3_mutex_alloc(X)    ((sqlite3_mutex*)8)
-#define sqlite3_mutex_free(X)
-#define sqlite3_mutex_enter(X)
-#define sqlite3_mutex_try(X)      SQLITE_OK
-#define sqlite3_mutex_leave(X)
-#define sqlite3_mutex_held(X)     ((void)(X),1)
-#define sqlite3_mutex_notheld(X)  ((void)(X),1)
-#endif /* SQLITE_THREADSAFE==0 */
-
-
-/*
-** Figure out if we are dealing with Unix, Windows, or some other
-** operating system.  After the following block of preprocess macros,
-** all of SQLITE_OS_UNIX, SQLITE_OS_WIN, and SQLITE_OS_OTHER 
-** will defined to either 1 or 0.  One of the four will be 1.  The other 
-** three will be 0.
-*/
-#if defined(SQLITE_OS_OTHER)
-# if SQLITE_OS_OTHER==1
-#   undef SQLITE_OS_UNIX
-#   define SQLITE_OS_UNIX 0
-#   undef SQLITE_OS_WIN
-#   define SQLITE_OS_WIN 0
-# else
-#   undef SQLITE_OS_OTHER
-# endif
-#endif
-#if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER)
-# define SQLITE_OS_OTHER 0
-# ifndef SQLITE_OS_WIN
-#   if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) \
-                       || defined(__MINGW32__) || defined(__BORLANDC__)
-#     define SQLITE_OS_WIN 1
-#     define SQLITE_OS_UNIX 0
-#   else
-#     define SQLITE_OS_WIN 0
-#     define SQLITE_OS_UNIX 1
-#  endif
-# else
-#  define SQLITE_OS_UNIX 0
-# endif
-#else
-# ifndef SQLITE_OS_WIN
-#  define SQLITE_OS_WIN 0
-# endif
-#endif
-
-#if SQLITE_OS_UNIX
-# include <unistd.h>
-#endif
-#if SQLITE_OS_WIN
-# include <windows.h>
-# include <io.h>
-#endif
-
-
-/************************ Object Definitions ******************************/
-
-/* Forward declaration of all object types */
-typedef struct quotaGroup quotaGroup;
-typedef struct quotaConn quotaConn;
-typedef struct quotaFile quotaFile;
-
-/*
-** A "quota group" is a collection of files whose collective size we want
-** to limit.  Each quota group is defined by a GLOB pattern.
-**
-** There is an instance of the following object for each defined quota
-** group.  This object records the GLOB pattern that defines which files
-** belong to the quota group.  The object also remembers the size limit
-** for the group (the quota) and the callback to be invoked when the
-** sum of the sizes of the files within the group goes over the limit.
-**
-** A quota group must be established (using sqlite3_quota_set(...))
-** prior to opening any of the database connections that access files
-** within the quota group.
-*/
-struct quotaGroup {
-  const char *zPattern;          /* Filename pattern to be quotaed */
-  sqlite3_int64 iLimit;          /* Upper bound on total file size */
-  sqlite3_int64 iSize;           /* Current size of all files */
-  void (*xCallback)(             /* Callback invoked when going over quota */
-     const char *zFilename,         /* Name of file whose size increases */
-     sqlite3_int64 *piLimit,        /* IN/OUT: The current limit */
-     sqlite3_int64 iSize,           /* Total size of all files in the group */
-     void *pArg                     /* Client data */
-  );
-  void *pArg;                    /* Third argument to the xCallback() */
-  void (*xDestroy)(void*);       /* Optional destructor for pArg */
-  quotaGroup *pNext, **ppPrev;   /* Doubly linked list of all quota objects */
-  quotaFile *pFiles;             /* Files within this group */
-};
-
-/*
-** An instance of this structure represents a single file that is part
-** of a quota group.  A single file can be opened multiple times.  In
-** order keep multiple openings of the same file from causing the size
-** of the file to count against the quota multiple times, each file
-** has a unique instance of this object and multiple open connections
-** to the same file each point to a single instance of this object.
-*/
-struct quotaFile {
-  char *zFilename;                /* Name of this file */
-  quotaGroup *pGroup;             /* Quota group to which this file belongs */
-  sqlite3_int64 iSize;            /* Current size of this file */
-  int nRef;                       /* Number of times this file is open */
-  int deleteOnClose;              /* True to delete this file when it closes */
-  quotaFile *pNext, **ppPrev;     /* Linked list of files in the same group */
-};
-
-/*
-** An instance of the following object represents each open connection
-** to a file that participates in quota tracking.  This object is a 
-** subclass of sqlite3_file.  The sqlite3_file object for the underlying
-** VFS is appended to this structure.
-*/
-struct quotaConn {
-  sqlite3_file base;              /* Base class - must be first */
-  quotaFile *pFile;               /* The underlying file */
-  /* The underlying VFS sqlite3_file is appended to this object */
-};
-
-/*
-** An instance of the following object records the state of an
-** open file.  This object is opaque to all users - the internal
-** structure is only visible to the functions below.
-*/
-struct quota_FILE {
-  FILE *f;                /* Open stdio file pointer */
-  sqlite3_int64 iOfst;    /* Current offset into the file */
-  quotaFile *pFile;       /* The file record in the quota system */
-#if SQLITE_OS_WIN
-  char *zMbcsName;        /* Full MBCS pathname of the file */
-#endif
-};
-
-
-/************************* Global Variables **********************************/
-/*
-** All global variables used by this file are containing within the following
-** gQuota structure.
-*/
-static struct {
-  /* The pOrigVfs is the real, original underlying VFS implementation.
-  ** Most operations pass-through to the real VFS.  This value is read-only
-  ** during operation.  It is only modified at start-time and thus does not
-  ** require a mutex.
-  */
-  sqlite3_vfs *pOrigVfs;
-
-  /* The sThisVfs is the VFS structure used by this shim.  It is initialized
-  ** at start-time and thus does not require a mutex
-  */
-  sqlite3_vfs sThisVfs;
-
-  /* The sIoMethods defines the methods used by sqlite3_file objects 
-  ** associated with this shim.  It is initialized at start-time and does
-  ** not require a mutex.
-  **
-  ** When the underlying VFS is called to open a file, it might return 
-  ** either a version 1 or a version 2 sqlite3_file object.  This shim
-  ** has to create a wrapper sqlite3_file of the same version.  Hence
-  ** there are two I/O method structures, one for version 1 and the other
-  ** for version 2.
-  */
-  sqlite3_io_methods sIoMethodsV1;
-  sqlite3_io_methods sIoMethodsV2;
-
-  /* True when this shim as been initialized.
-  */
-  int isInitialized;
-
-  /* For run-time access any of the other global data structures in this
-  ** shim, the following mutex must be held.
-  */
-  sqlite3_mutex *pMutex;
-
-  /* List of quotaGroup objects.
-  */
-  quotaGroup *pGroup;
-
-} gQuota;
-
-/************************* Utility Routines *********************************/
-/*
-** Acquire and release the mutex used to serialize access to the
-** list of quotaGroups.
-*/
-static void quotaEnter(void){ sqlite3_mutex_enter(gQuota.pMutex); }
-static void quotaLeave(void){ sqlite3_mutex_leave(gQuota.pMutex); }
-
-/* Count the number of open files in a quotaGroup 
-*/
-static int quotaGroupOpenFileCount(quotaGroup *pGroup){
-  int N = 0;
-  quotaFile *pFile = pGroup->pFiles;
-  while( pFile ){
-    if( pFile->nRef ) N++;
-    pFile = pFile->pNext;
-  }
-  return N;
-}
-
-/* Remove a file from a quota group.
-*/
-static void quotaRemoveFile(quotaFile *pFile){
-  quotaGroup *pGroup = pFile->pGroup;
-  pGroup->iSize -= pFile->iSize;
-  *pFile->ppPrev = pFile->pNext;
-  if( pFile->pNext ) pFile->pNext->ppPrev = pFile->ppPrev;
-  sqlite3_free(pFile);
-}
-
-/* Remove all files from a quota group.  It is always the case that
-** all files will be closed when this routine is called.
-*/
-static void quotaRemoveAllFiles(quotaGroup *pGroup){
-  while( pGroup->pFiles ){
-    assert( pGroup->pFiles->nRef==0 );
-    quotaRemoveFile(pGroup->pFiles);
-  }
-}
-
-
-/* If the reference count and threshold for a quotaGroup are both
-** zero, then destroy the quotaGroup.
-*/
-static void quotaGroupDeref(quotaGroup *pGroup){
-  if( pGroup->iLimit==0 && quotaGroupOpenFileCount(pGroup)==0 ){
-    quotaRemoveAllFiles(pGroup);
-    *pGroup->ppPrev = pGroup->pNext;
-    if( pGroup->pNext ) pGroup->pNext->ppPrev = pGroup->ppPrev;
-    if( pGroup->xDestroy ) pGroup->xDestroy(pGroup->pArg);
-    sqlite3_free(pGroup);
-  }
-}
-
-/*
-** Return TRUE if string z matches glob pattern zGlob.
-**
-** Globbing rules:
-**
-**      '*'       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.
-**
-**     /          Matches "/" or "\\"
-**
-*/
-static int quotaStrglob(const char *zGlob, const char *z){
-  int c, c2, cx;
-  int invert;
-  int seen;
-
-  while( (c = (*(zGlob++)))!=0 ){
-    if( c=='*' ){
-      while( (c=(*(zGlob++))) == '*' || c=='?' ){
-        if( c=='?' && (*(z++))==0 ) return 0;
-      }
-      if( c==0 ){
-        return 1;
-      }else if( c=='[' ){
-        while( *z && quotaStrglob(zGlob-1,z)==0 ){
-          z++;
-        }
-        return (*z)!=0;
-      }
-      cx = (c=='/') ? '\\' : c;
-      while( (c2 = (*(z++)))!=0 ){
-        while( c2!=c && c2!=cx ){
-          c2 = *(z++);
-          if( c2==0 ) return 0;
-        }
-        if( quotaStrglob(zGlob,z) ) return 1;
-      }
-      return 0;
-    }else if( c=='?' ){
-      if( (*(z++))==0 ) return 0;
-    }else if( c=='[' ){
-      int prior_c = 0;
-      seen = 0;
-      invert = 0;
-      c = *(z++);
-      if( c==0 ) return 0;
-      c2 = *(zGlob++);
-      if( c2=='^' ){
-        invert = 1;
-        c2 = *(zGlob++);
-      }
-      if( c2==']' ){
-        if( c==']' ) seen = 1;
-        c2 = *(zGlob++);
-      }
-      while( c2 && c2!=']' ){
-        if( c2=='-' && zGlob[0]!=']' && zGlob[0]!=0 && prior_c>0 ){
-          c2 = *(zGlob++);
-          if( c>=prior_c && c<=c2 ) seen = 1;
-          prior_c = 0;
-        }else{
-          if( c==c2 ){
-            seen = 1;
-          }
-          prior_c = c2;
-        }
-        c2 = *(zGlob++);
-      }
-      if( c2==0 || (seen ^ invert)==0 ) return 0;
-    }else if( c=='/' ){
-      if( z[0]!='/' && z[0]!='\\' ) return 0;
-      z++;
-    }else{
-      if( c!=(*(z++)) ) return 0;
-    }
-  }
-  return *z==0;
-}
-
-
-/* Find a quotaGroup given the filename.
-**
-** Return a pointer to the quotaGroup object. Return NULL if not found.
-*/
-static quotaGroup *quotaGroupFind(const char *zFilename){
-  quotaGroup *p;
-  for(p=gQuota.pGroup; p && quotaStrglob(p->zPattern, zFilename)==0;
-      p=p->pNext){}
-  return p;
-}
-
-/* Translate an sqlite3_file* that is really a quotaConn* into
-** the sqlite3_file* for the underlying original VFS.
-*/
-static sqlite3_file *quotaSubOpen(sqlite3_file *pConn){
-  quotaConn *p = (quotaConn*)pConn;
-  return (sqlite3_file*)&p[1];
-}
-
-/* Find a file in a quota group and return a pointer to that file.
-** Return NULL if the file is not in the group.
-*/
-static quotaFile *quotaFindFile(
-  quotaGroup *pGroup,     /* Group in which to look for the file */
-  const char *zName,      /* Full pathname of the file */
-  int createFlag          /* Try to create the file if not found */
-){
-  quotaFile *pFile = pGroup->pFiles;
-  while( pFile && strcmp(pFile->zFilename, zName)!=0 ){
-    pFile = pFile->pNext;
-  }
-  if( pFile==0 && createFlag ){
-    int nName = (int)(strlen(zName) & 0x3fffffff);
-    pFile = (quotaFile *)sqlite3_malloc( sizeof(*pFile) + nName + 1 );
-    if( pFile ){
-      memset(pFile, 0, sizeof(*pFile));
-      pFile->zFilename = (char*)&pFile[1];
-      memcpy(pFile->zFilename, zName, nName+1);
-      pFile->pNext = pGroup->pFiles;
-      if( pGroup->pFiles ) pGroup->pFiles->ppPrev = &pFile->pNext;
-      pFile->ppPrev = &pGroup->pFiles;
-      pGroup->pFiles = pFile;
-      pFile->pGroup = pGroup;
-    }
-  }
-  return pFile;
-}
-/*
-** Translate UTF8 to MBCS for use in fopen() calls.  Return a pointer to the
-** translated text..  Call quota_mbcs_free() to deallocate any memory
-** used to store the returned pointer when done.
-*/
-static char *quota_utf8_to_mbcs(const char *zUtf8){
-#if SQLITE_OS_WIN
-  size_t n;          /* Bytes in zUtf8 */
-  int nWide;         /* number of UTF-16 characters */
-  int nMbcs;         /* Bytes of MBCS */
-  LPWSTR zTmpWide;   /* The UTF16 text */
-  char *zMbcs;       /* The MBCS text */
-  int codepage;      /* Code page used by fopen() */
-
-  n = strlen(zUtf8);
-  nWide = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, NULL, 0);
-  if( nWide==0 ) return 0;
-  zTmpWide = (LPWSTR)sqlite3_malloc( (nWide+1)*sizeof(zTmpWide[0]) );
-  if( zTmpWide==0 ) return 0;
-  MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zTmpWide, nWide);
-  codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
-  nMbcs = WideCharToMultiByte(codepage, 0, zTmpWide, nWide, 0, 0, 0, 0);
-  zMbcs = nMbcs ? (char*)sqlite3_malloc( nMbcs+1 ) : 0;
-  if( zMbcs ){
-    WideCharToMultiByte(codepage, 0, zTmpWide, nWide, zMbcs, nMbcs, 0, 0);
-  }
-  sqlite3_free(zTmpWide);
-  return zMbcs;
-#else
-  return (char*)zUtf8;  /* No-op on unix */
-#endif  
-}
-
-/*
-** Deallocate any memory allocated by quota_utf8_to_mbcs().
-*/
-static void quota_mbcs_free(char *zOld){
-#if SQLITE_OS_WIN
-  sqlite3_free(zOld);
-#else
-  /* No-op on unix */
-#endif  
-}
-
-/************************* VFS Method Wrappers *****************************/
-/*
-** This is the xOpen method used for the "quota" VFS.
-**
-** Most of the work is done by the underlying original VFS.  This method
-** simply links the new file into the appropriate quota group if it is a
-** file that needs to be tracked.
-*/
-static int quotaOpen(
-  sqlite3_vfs *pVfs,          /* The quota VFS */
-  const char *zName,          /* Name of file to be opened */
-  sqlite3_file *pConn,        /* Fill in this file descriptor */
-  int flags,                  /* Flags to control the opening */
-  int *pOutFlags              /* Flags showing results of opening */
-){
-  int rc;                                    /* Result code */         
-  quotaConn *pQuotaOpen;                     /* The new quota file descriptor */
-  quotaFile *pFile;                          /* Corresponding quotaFile obj */
-  quotaGroup *pGroup;                        /* The group file belongs to */
-  sqlite3_file *pSubOpen;                    /* Real file descriptor */
-  sqlite3_vfs *pOrigVfs = gQuota.pOrigVfs;   /* Real VFS */
-
-  /* If the file is not a main database file or a WAL, then use the
-  ** normal xOpen method.
-  */
-  if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){
-    return pOrigVfs->xOpen(pOrigVfs, zName, pConn, flags, pOutFlags);
-  }
-
-  /* If the name of the file does not match any quota group, then
-  ** use the normal xOpen method.
-  */
-  quotaEnter();
-  pGroup = quotaGroupFind(zName);
-  if( pGroup==0 ){
-    rc = pOrigVfs->xOpen(pOrigVfs, zName, pConn, flags, pOutFlags);
-  }else{
-    /* If we get to this point, it means the file needs to be quota tracked.
-    */
-    pQuotaOpen = (quotaConn*)pConn;
-    pSubOpen = quotaSubOpen(pConn);
-    rc = pOrigVfs->xOpen(pOrigVfs, zName, pSubOpen, flags, pOutFlags);
-    if( rc==SQLITE_OK ){
-      pFile = quotaFindFile(pGroup, zName, 1);
-      if( pFile==0 ){
-        quotaLeave();
-        pSubOpen->pMethods->xClose(pSubOpen);
-        return SQLITE_NOMEM;
-      }
-      pFile->deleteOnClose = (flags & SQLITE_OPEN_DELETEONCLOSE)!=0;
-      pFile->nRef++;
-      pQuotaOpen->pFile = pFile;
-      if( pSubOpen->pMethods->iVersion==1 ){
-        pQuotaOpen->base.pMethods = &gQuota.sIoMethodsV1;
-      }else{
-        pQuotaOpen->base.pMethods = &gQuota.sIoMethodsV2;
-      }
-    }
-  }
-  quotaLeave();
-  return rc;
-}
-
-/*
-** This is the xDelete method used for the "quota" VFS.
-**
-** If the file being deleted is part of the quota group, then reduce
-** the size of the quota group accordingly.  And remove the file from
-** the set of files in the quota group.
-*/
-static int quotaDelete(
-  sqlite3_vfs *pVfs,          /* The quota VFS */
-  const char *zName,          /* Name of file to be deleted */
-  int syncDir                 /* Do a directory sync after deleting */
-){
-  int rc;                                    /* Result code */         
-  quotaFile *pFile;                          /* Files in the quota */
-  quotaGroup *pGroup;                        /* The group file belongs to */
-  sqlite3_vfs *pOrigVfs = gQuota.pOrigVfs;   /* Real VFS */
-
-  /* Do the actual file delete */
-  rc = pOrigVfs->xDelete(pOrigVfs, zName, syncDir);
-
-  /* If the file just deleted is a member of a quota group, then remove
-  ** it from that quota group.
-  */
-  if( rc==SQLITE_OK ){
-    quotaEnter();
-    pGroup = quotaGroupFind(zName);
-    if( pGroup ){
-      pFile = quotaFindFile(pGroup, zName, 0);
-      if( pFile ){
-        if( pFile->nRef ){
-          pFile->deleteOnClose = 1;
-        }else{
-          quotaRemoveFile(pFile);
-          quotaGroupDeref(pGroup);
-        }
-      }
-    }
-    quotaLeave();
-  }
-  return rc;
-}
-
-
-/************************ I/O Method Wrappers *******************************/
-
-/* xClose requests get passed through to the original VFS.  But we
-** also have to unlink the quotaConn from the quotaFile and quotaGroup.
-** The quotaFile and/or quotaGroup are freed if they are no longer in use.
-*/
-static int quotaClose(sqlite3_file *pConn){
-  quotaConn *p = (quotaConn*)pConn;
-  quotaFile *pFile = p->pFile;
-  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
-  int rc;
-  rc = pSubOpen->pMethods->xClose(pSubOpen);
-  quotaEnter();
-  pFile->nRef--;
-  if( pFile->nRef==0 ){
-    quotaGroup *pGroup = pFile->pGroup;
-    if( pFile->deleteOnClose ){
-      gQuota.pOrigVfs->xDelete(gQuota.pOrigVfs, pFile->zFilename, 0);
-      quotaRemoveFile(pFile);
-    }
-    quotaGroupDeref(pGroup);
-  }
-  quotaLeave();
-  return rc;
-}
-
-/* Pass xRead requests directory thru to the original VFS without
-** further processing.
-*/
-static int quotaRead(
-  sqlite3_file *pConn,
-  void *pBuf,
-  int iAmt,
-  sqlite3_int64 iOfst
-){
-  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
-  return pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst);
-}
-
-/* Check xWrite requests to see if they expand the file.  If they do,
-** the perform a quota check before passing them through to the
-** original VFS.
-*/
-static int quotaWrite(
-  sqlite3_file *pConn,
-  const void *pBuf,
-  int iAmt,
-  sqlite3_int64 iOfst
-){
-  quotaConn *p = (quotaConn*)pConn;
-  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
-  sqlite3_int64 iEnd = iOfst+iAmt;
-  quotaGroup *pGroup;
-  quotaFile *pFile = p->pFile;
-  sqlite3_int64 szNew;
-
-  if( pFile->iSize<iEnd ){
-    pGroup = pFile->pGroup;
-    quotaEnter();
-    szNew = pGroup->iSize - pFile->iSize + iEnd;
-    if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){
-      if( pGroup->xCallback ){
-        pGroup->xCallback(pFile->zFilename, &pGroup->iLimit, szNew, 
-                          pGroup->pArg);
-      }
-      if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){
-        quotaLeave();
-        return SQLITE_FULL;
-      }
-    }
-    pGroup->iSize = szNew;
-    pFile->iSize = iEnd;
-    quotaLeave();
-  }
-  return pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst);
-}
-
-/* Pass xTruncate requests thru to the original VFS.  If the
-** success, update the file size.
-*/
-static int quotaTruncate(sqlite3_file *pConn, sqlite3_int64 size){
-  quotaConn *p = (quotaConn*)pConn;
-  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
-  int rc = pSubOpen->pMethods->xTruncate(pSubOpen, size);
-  quotaFile *pFile = p->pFile;
-  quotaGroup *pGroup;
-  if( rc==SQLITE_OK ){
-    quotaEnter();
-    pGroup = pFile->pGroup;
-    pGroup->iSize -= pFile->iSize;
-    pFile->iSize = size;
-    pGroup->iSize += size;
-    quotaLeave();
-  }
-  return rc;
-}
-
-/* Pass xSync requests through to the original VFS without change
-*/
-static int quotaSync(sqlite3_file *pConn, int flags){
-  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
-  return pSubOpen->pMethods->xSync(pSubOpen, flags);
-}
-
-/* Pass xFileSize requests through to the original VFS but then
-** update the quotaGroup with the new size before returning.
-*/
-static int quotaFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
-  quotaConn *p = (quotaConn*)pConn;
-  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
-  quotaFile *pFile = p->pFile;
-  quotaGroup *pGroup;
-  sqlite3_int64 sz;
-  int rc;
-
-  rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
-  if( rc==SQLITE_OK ){
-    quotaEnter();
-    pGroup = pFile->pGroup;
-    pGroup->iSize -= pFile->iSize;
-    pFile->iSize = sz;
-    pGroup->iSize += sz;
-    quotaLeave();
-    *pSize = sz;
-  }
-  return rc;
-}
-
-/* Pass xLock requests through to the original VFS unchanged.
-*/
-static int quotaLock(sqlite3_file *pConn, int lock){
-  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
-  return pSubOpen->pMethods->xLock(pSubOpen, lock);
-}
-
-/* Pass xUnlock requests through to the original VFS unchanged.
-*/
-static int quotaUnlock(sqlite3_file *pConn, int lock){
-  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
-  return pSubOpen->pMethods->xUnlock(pSubOpen, lock);
-}
-
-/* Pass xCheckReservedLock requests through to the original VFS unchanged.
-*/
-static int quotaCheckReservedLock(sqlite3_file *pConn, int *pResOut){
-  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
-  return pSubOpen->pMethods->xCheckReservedLock(pSubOpen, pResOut);
-}
-
-/* Pass xFileControl requests through to the original VFS unchanged.
-*/
-static int quotaFileControl(sqlite3_file *pConn, int op, void *pArg){
-  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
-  int rc = pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg);
-#if defined(SQLITE_FCNTL_VFSNAME)
-  if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
-    *(char**)pArg = sqlite3_mprintf("quota/%z", *(char**)pArg);
-  }
-#endif
-  return rc;
-}
-
-/* Pass xSectorSize requests through to the original VFS unchanged.
-*/
-static int quotaSectorSize(sqlite3_file *pConn){
-  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
-  return pSubOpen->pMethods->xSectorSize(pSubOpen);
-}
-
-/* Pass xDeviceCharacteristics requests through to the original VFS unchanged.
-*/
-static int quotaDeviceCharacteristics(sqlite3_file *pConn){
-  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
-  return pSubOpen->pMethods->xDeviceCharacteristics(pSubOpen);
-}
-
-/* Pass xShmMap requests through to the original VFS unchanged.
-*/
-static int quotaShmMap(
-  sqlite3_file *pConn,            /* Handle open on database file */
-  int iRegion,                    /* Region to retrieve */
-  int szRegion,                   /* Size of regions */
-  int bExtend,                    /* True to extend file if necessary */
-  void volatile **pp              /* OUT: Mapped memory */
-){
-  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
-  return pSubOpen->pMethods->xShmMap(pSubOpen, iRegion, szRegion, bExtend, pp);
-}
-
-/* Pass xShmLock requests through to the original VFS unchanged.
-*/
-static int quotaShmLock(
-  sqlite3_file *pConn,       /* Database file holding the shared memory */
-  int ofst,                  /* First lock to acquire or release */
-  int n,                     /* Number of locks to acquire or release */
-  int flags                  /* What to do with the lock */
-){
-  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
-  return pSubOpen->pMethods->xShmLock(pSubOpen, ofst, n, flags);
-}
-
-/* Pass xShmBarrier requests through to the original VFS unchanged.
-*/
-static void quotaShmBarrier(sqlite3_file *pConn){
-  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
-  pSubOpen->pMethods->xShmBarrier(pSubOpen);
-}
-
-/* Pass xShmUnmap requests through to the original VFS unchanged.
-*/
-static int quotaShmUnmap(sqlite3_file *pConn, int deleteFlag){
-  sqlite3_file *pSubOpen = quotaSubOpen(pConn);
-  return pSubOpen->pMethods->xShmUnmap(pSubOpen, deleteFlag);
-}
-
-/************************** Public Interfaces *****************************/
-/*
-** Initialize the quota VFS shim.  Use the VFS named zOrigVfsName
-** as the VFS that does the actual work.  Use the default if
-** zOrigVfsName==NULL.  
-**
-** The quota VFS shim is named "quota".  It will become the default
-** VFS if makeDefault is non-zero.
-**
-** THIS ROUTINE IS NOT THREADSAFE.  Call this routine exactly once
-** during start-up.
-*/
-int sqlite3_quota_initialize(const char *zOrigVfsName, int makeDefault){
-  sqlite3_vfs *pOrigVfs;
-  if( gQuota.isInitialized ) return SQLITE_MISUSE;
-  pOrigVfs = sqlite3_vfs_find(zOrigVfsName);
-  if( pOrigVfs==0 ) return SQLITE_ERROR;
-  assert( pOrigVfs!=&gQuota.sThisVfs );
-  gQuota.pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
-  if( !gQuota.pMutex ){
-    return SQLITE_NOMEM;
-  }
-  gQuota.isInitialized = 1;
-  gQuota.pOrigVfs = pOrigVfs;
-  gQuota.sThisVfs = *pOrigVfs;
-  gQuota.sThisVfs.xOpen = quotaOpen;
-  gQuota.sThisVfs.xDelete = quotaDelete;
-  gQuota.sThisVfs.szOsFile += sizeof(quotaConn);
-  gQuota.sThisVfs.zName = "quota";
-  gQuota.sIoMethodsV1.iVersion = 1;
-  gQuota.sIoMethodsV1.xClose = quotaClose;
-  gQuota.sIoMethodsV1.xRead = quotaRead;
-  gQuota.sIoMethodsV1.xWrite = quotaWrite;
-  gQuota.sIoMethodsV1.xTruncate = quotaTruncate;
-  gQuota.sIoMethodsV1.xSync = quotaSync;
-  gQuota.sIoMethodsV1.xFileSize = quotaFileSize;
-  gQuota.sIoMethodsV1.xLock = quotaLock;
-  gQuota.sIoMethodsV1.xUnlock = quotaUnlock;
-  gQuota.sIoMethodsV1.xCheckReservedLock = quotaCheckReservedLock;
-  gQuota.sIoMethodsV1.xFileControl = quotaFileControl;
-  gQuota.sIoMethodsV1.xSectorSize = quotaSectorSize;
-  gQuota.sIoMethodsV1.xDeviceCharacteristics = quotaDeviceCharacteristics;
-  gQuota.sIoMethodsV2 = gQuota.sIoMethodsV1;
-  gQuota.sIoMethodsV2.iVersion = 2;
-  gQuota.sIoMethodsV2.xShmMap = quotaShmMap;
-  gQuota.sIoMethodsV2.xShmLock = quotaShmLock;
-  gQuota.sIoMethodsV2.xShmBarrier = quotaShmBarrier;
-  gQuota.sIoMethodsV2.xShmUnmap = quotaShmUnmap;
-  sqlite3_vfs_register(&gQuota.sThisVfs, makeDefault);
-  return SQLITE_OK;
-}
-
-/*
-** Shutdown the quota system.
-**
-** All SQLite database connections must be closed before calling this
-** routine.
-**
-** THIS ROUTINE IS NOT THREADSAFE.  Call this routine exactly once while
-** shutting down in order to free all remaining quota groups.
-*/
-int sqlite3_quota_shutdown(void){
-  quotaGroup *pGroup;
-  if( gQuota.isInitialized==0 ) return SQLITE_MISUSE;
-  for(pGroup=gQuota.pGroup; pGroup; pGroup=pGroup->pNext){
-    if( quotaGroupOpenFileCount(pGroup)>0 ) return SQLITE_MISUSE;
-  }
-  while( gQuota.pGroup ){
-    pGroup = gQuota.pGroup;
-    gQuota.pGroup = pGroup->pNext;
-    pGroup->iLimit = 0;
-    assert( quotaGroupOpenFileCount(pGroup)==0 );
-    quotaGroupDeref(pGroup);
-  }
-  gQuota.isInitialized = 0;
-  sqlite3_mutex_free(gQuota.pMutex);
-  sqlite3_vfs_unregister(&gQuota.sThisVfs);
-  memset(&gQuota, 0, sizeof(gQuota));
-  return SQLITE_OK;
-}
-
-/*
-** Create or destroy a quota group.
-**
-** The quota group is defined by the zPattern.  When calling this routine
-** with a zPattern for a quota group that already exists, this routine
-** merely updates the iLimit, xCallback, and pArg values for that quota
-** group.  If zPattern is new, then a new quota group is created.
-**
-** If the iLimit for a quota group is set to zero, then the quota group
-** is disabled and will be deleted when the last database connection using
-** the quota group is closed.
-**
-** Calling this routine on a zPattern that does not exist and with a
-** zero iLimit is a no-op.
-**
-** A quota group must exist with a non-zero iLimit prior to opening
-** database connections if those connections are to participate in the
-** quota group.  Creating a quota group does not affect database connections
-** that are already open.
-*/
-int sqlite3_quota_set(
-  const char *zPattern,           /* The filename pattern */
-  sqlite3_int64 iLimit,           /* New quota to set for this quota group */
-  void (*xCallback)(              /* Callback invoked when going over quota */
-     const char *zFilename,         /* Name of file whose size increases */
-     sqlite3_int64 *piLimit,        /* IN/OUT: The current limit */
-     sqlite3_int64 iSize,           /* Total size of all files in the group */
-     void *pArg                     /* Client data */
-  ),
-  void *pArg,                     /* client data passed thru to callback */
-  void (*xDestroy)(void*)         /* Optional destructor for pArg */
-){
-  quotaGroup *pGroup;
-  quotaEnter();
-  pGroup = gQuota.pGroup;
-  while( pGroup && strcmp(pGroup->zPattern, zPattern)!=0 ){
-    pGroup = pGroup->pNext;
-  }
-  if( pGroup==0 ){
-    int nPattern = (int)(strlen(zPattern) & 0x3fffffff);
-    if( iLimit<=0 ){
-      quotaLeave();
-      return SQLITE_OK;
-    }
-    pGroup = (quotaGroup *)sqlite3_malloc( sizeof(*pGroup) + nPattern + 1 );
-    if( pGroup==0 ){
-      quotaLeave();
-      return SQLITE_NOMEM;
-    }
-    memset(pGroup, 0, sizeof(*pGroup));
-    pGroup->zPattern = (char*)&pGroup[1];
-    memcpy((char *)pGroup->zPattern, zPattern, nPattern+1);
-    if( gQuota.pGroup ) gQuota.pGroup->ppPrev = &pGroup->pNext;
-    pGroup->pNext = gQuota.pGroup;
-    pGroup->ppPrev = &gQuota.pGroup;
-    gQuota.pGroup = pGroup;
-  }
-  pGroup->iLimit = iLimit;
-  pGroup->xCallback = xCallback;
-  if( pGroup->xDestroy && pGroup->pArg!=pArg ){
-    pGroup->xDestroy(pGroup->pArg);
-  }
-  pGroup->pArg = pArg;
-  pGroup->xDestroy = xDestroy;
-  quotaGroupDeref(pGroup);
-  quotaLeave();
-  return SQLITE_OK;
-}
-
-/*
-** Bring the named file under quota management.  Or if it is already under
-** management, update its size.
-*/
-int sqlite3_quota_file(const char *zFilename){
-  char *zFull;
-  sqlite3_file *fd;
-  int rc;
-  int outFlags = 0;
-  sqlite3_int64 iSize;
-  int nAlloc = gQuota.sThisVfs.szOsFile + gQuota.sThisVfs.mxPathname+2;
-
-  /* Allocate space for a file-handle and the full path for file zFilename */
-  fd = (sqlite3_file *)sqlite3_malloc(nAlloc);
-  if( fd==0 ){
-    rc = SQLITE_NOMEM;
-  }else{
-    zFull = &((char *)fd)[gQuota.sThisVfs.szOsFile];
-    rc = gQuota.pOrigVfs->xFullPathname(gQuota.pOrigVfs, zFilename,
-        gQuota.sThisVfs.mxPathname+1, zFull);
-  }
-
-  if( rc==SQLITE_OK ){
-    zFull[strlen(zFull)+1] = '\0';
-    rc = quotaOpen(&gQuota.sThisVfs, zFull, fd, 
-                   SQLITE_OPEN_READONLY | SQLITE_OPEN_MAIN_DB, &outFlags);
-    if( rc==SQLITE_OK ){
-      fd->pMethods->xFileSize(fd, &iSize);
-      fd->pMethods->xClose(fd);
-    }else if( rc==SQLITE_CANTOPEN ){
-      quotaGroup *pGroup;
-      quotaFile *pFile;
-      quotaEnter();
-      pGroup = quotaGroupFind(zFull);
-      if( pGroup ){
-        pFile = quotaFindFile(pGroup, zFull, 0);
-        if( pFile ) quotaRemoveFile(pFile);
-      }
-      quotaLeave();
-    }
-  }
-
-  sqlite3_free(fd);
-  return rc;
-}
-
-/*
-** Open a potentially quotaed file for I/O.
-*/
-quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode){
-  quota_FILE *p = 0;
-  char *zFull = 0;
-  char *zFullTranslated = 0;
-  int rc;
-  quotaGroup *pGroup;
-  quotaFile *pFile;
-
-  zFull = (char*)sqlite3_malloc(gQuota.sThisVfs.mxPathname + 1);
-  if( zFull==0 ) return 0;
-  rc = gQuota.pOrigVfs->xFullPathname(gQuota.pOrigVfs, zFilename,
-                                      gQuota.sThisVfs.mxPathname+1, zFull);
-  if( rc ) goto quota_fopen_error;
-  p = (quota_FILE*)sqlite3_malloc(sizeof(*p));
-  if( p==0 ) goto quota_fopen_error;
-  memset(p, 0, sizeof(*p));
-  zFullTranslated = quota_utf8_to_mbcs(zFull);
-  if( zFullTranslated==0 ) goto quota_fopen_error;
-  p->f = fopen(zFullTranslated, zMode);
-  if( p->f==0 ) goto quota_fopen_error;
-  quotaEnter();
-  pGroup = quotaGroupFind(zFull);
-  if( pGroup ){
-    pFile = quotaFindFile(pGroup, zFull, 1);
-    if( pFile==0 ){
-      quotaLeave();
-      goto quota_fopen_error;
-    }
-    pFile->nRef++;
-    p->pFile = pFile;
-  }
-  quotaLeave();
-  sqlite3_free(zFull);
-#if SQLITE_OS_WIN
-  p->zMbcsName = zFullTranslated;
-#endif
-  return p;
-
-quota_fopen_error:
-  quota_mbcs_free(zFullTranslated);
-  sqlite3_free(zFull);
-  if( p && p->f ) fclose(p->f);
-  sqlite3_free(p);
-  return 0;
-}
-
-/*
-** Read content from a quota_FILE
-*/
-size_t sqlite3_quota_fread(
-  void *pBuf,            /* Store the content here */
-  size_t size,           /* Size of each element */
-  size_t nmemb,          /* Number of elements to read */
-  quota_FILE *p          /* Read from this quota_FILE object */
-){
-  return fread(pBuf, size, nmemb, p->f);
-}
-
-/*
-** Write content into a quota_FILE.  Invoke the quota callback and block
-** the write if we exceed quota.
-*/
-size_t sqlite3_quota_fwrite(
-  const void *pBuf,      /* Take content to write from here */
-  size_t size,           /* Size of each element */
-  size_t nmemb,          /* Number of elements */
-  quota_FILE *p          /* Write to this quota_FILE objecct */
-){
-  sqlite3_int64 iOfst;
-  sqlite3_int64 iEnd;
-  sqlite3_int64 szNew;
-  quotaFile *pFile;
-  size_t rc;
-
-  iOfst = ftell(p->f);
-  iEnd = iOfst + size*nmemb;
-  pFile = p->pFile;
-  if( pFile && pFile->iSize<iEnd ){
-    quotaGroup *pGroup = pFile->pGroup;
-    quotaEnter();
-    szNew = pGroup->iSize - pFile->iSize + iEnd;
-    if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){
-      if( pGroup->xCallback ){
-        pGroup->xCallback(pFile->zFilename, &pGroup->iLimit, szNew, 
-                          pGroup->pArg);
-      }
-      if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){
-        iEnd = pGroup->iLimit - pGroup->iSize + pFile->iSize;
-        nmemb = (size_t)((iEnd - iOfst)/size);
-        iEnd = iOfst + size*nmemb;
-        szNew = pGroup->iSize - pFile->iSize + iEnd;
-      }
-    }
-    pGroup->iSize = szNew;
-    pFile->iSize = iEnd;
-    quotaLeave();
-  }else{
-    pFile = 0;
-  }
-  rc = fwrite(pBuf, size, nmemb, p->f);
-
-  /* If the write was incomplete, adjust the file size and group size
-  ** downward */
-  if( rc<nmemb && pFile ){
-    size_t nWritten = rc>=0 ? rc : 0;
-    sqlite3_int64 iNewEnd = iOfst + size*nWritten;
-    if( iNewEnd<iEnd ) iNewEnd = iEnd;
-    quotaEnter();
-    pFile->pGroup->iSize += iNewEnd - pFile->iSize;
-    pFile->iSize = iNewEnd;
-    quotaLeave();
-  }
-  return rc;
-}
-
-/*
-** Close an open quota_FILE stream.
-*/
-int sqlite3_quota_fclose(quota_FILE *p){
-  int rc;
-  quotaFile *pFile;
-  rc = fclose(p->f);
-  pFile = p->pFile;
-  if( pFile ){
-    quotaEnter();
-    pFile->nRef--;
-    if( pFile->nRef==0 ){
-      quotaGroup *pGroup = pFile->pGroup;
-      if( pFile->deleteOnClose ){
-        gQuota.pOrigVfs->xDelete(gQuota.pOrigVfs, pFile->zFilename, 0);
-        quotaRemoveFile(pFile);
-      }
-      quotaGroupDeref(pGroup);
-    }
-    quotaLeave();
-  }
-#if SQLITE_OS_WIN
-  quota_mbcs_free(p->zMbcsName);
-#endif
-  sqlite3_free(p);
-  return rc;
-}
-
-/*
-** Flush memory buffers for a quota_FILE to disk.
-*/
-int sqlite3_quota_fflush(quota_FILE *p, int doFsync){
-  int rc;
-  rc = fflush(p->f);
-  if( rc==0 && doFsync ){
-#if SQLITE_OS_UNIX
-    rc = fsync(fileno(p->f));
-#endif
-#if SQLITE_OS_WIN
-    rc = _commit(_fileno(p->f));
-#endif
-  }
-  return rc!=0;
-}
-
-/*
-** Seek on a quota_FILE stream.
-*/
-int sqlite3_quota_fseek(quota_FILE *p, long offset, int whence){
-  return fseek(p->f, offset, whence);
-}
-
-/*
-** rewind a quota_FILE stream.
-*/
-void sqlite3_quota_rewind(quota_FILE *p){
-  rewind(p->f);
-}
-
-/*
-** Tell the current location of a quota_FILE stream.
-*/
-long sqlite3_quota_ftell(quota_FILE *p){
-  return ftell(p->f);
-}
-
-/*
-** Test the error indicator for the given file.
-*/
-int sqlite3_quota_ferror(quota_FILE *p){
-  return ferror(p->f);
-}
-
-/*
-** Truncate a file to szNew bytes.
-*/
-int sqlite3_quota_ftruncate(quota_FILE *p, sqlite3_int64 szNew){
-  quotaFile *pFile = p->pFile;
-  int rc;
-  if( (pFile = p->pFile)!=0 && pFile->iSize<szNew ){
-    quotaGroup *pGroup;
-    if( pFile->iSize<szNew ){
-      /* This routine cannot be used to extend a file that is under
-      ** quota management.  Only true truncation is allowed. */
-      return -1;
-    }
-    pGroup = pFile->pGroup;
-    quotaEnter();
-    pGroup->iSize += szNew - pFile->iSize;
-    quotaLeave();
-  }
-#if SQLITE_OS_UNIX
-  rc = ftruncate(fileno(p->f), szNew);
-#endif
-#if SQLITE_OS_WIN
-  rc = _chsize_s(_fileno(p->f), szNew);
-#endif
-  if( pFile && rc==0 ){
-    quotaGroup *pGroup = pFile->pGroup;
-    quotaEnter();
-    pGroup->iSize += szNew - pFile->iSize;
-    pFile->iSize = szNew;
-    quotaLeave();
-  }
-  return rc;
-}
-
-/*
-** Determine the time that the given file was last modified, in
-** seconds size 1970.  Write the result into *pTime.  Return 0 on
-** success and non-zero on any kind of error.
-*/
-int sqlite3_quota_file_mtime(quota_FILE *p, time_t *pTime){
-  int rc;
-#if SQLITE_OS_UNIX
-  struct stat buf;
-  rc = fstat(fileno(p->f), &buf);
-#endif
-#if SQLITE_OS_WIN
-  struct _stati64 buf;
-  rc = _stati64(p->zMbcsName, &buf);
-#endif
-  if( rc==0 ) *pTime = buf.st_mtime;
-  return rc;
-}
-
-/*
-** Return the true size of the file, as reported by the operating
-** system.
-*/
-sqlite3_int64 sqlite3_quota_file_truesize(quota_FILE *p){
-  int rc;
-#if SQLITE_OS_UNIX
-  struct stat buf;
-  rc = fstat(fileno(p->f), &buf);
-#endif
-#if SQLITE_OS_WIN
-  struct _stati64 buf;
-  rc = _stati64(p->zMbcsName, &buf);
-#endif
-  return rc==0 ? buf.st_size : -1;
-}
-
-/*
-** Return the size of the file, as it is known to the quota subsystem.
-*/
-sqlite3_int64 sqlite3_quota_file_size(quota_FILE *p){
-  return p->pFile ? p->pFile->iSize : -1;
-}
- 
-/*
-** Determine the amount of data in bytes available for reading
-** in the given file.
-*/
-long sqlite3_quota_file_available(quota_FILE *p){
-  FILE* f = p->f;
-  long pos1, pos2;
-  int rc;
-  pos1 = ftell(f);
-  if ( pos1 < 0 ) return -1;
-  rc = fseek(f, 0, SEEK_END);
-  if ( rc != 0 ) return -1;
-  pos2 = ftell(f);
-  if ( pos2 < 0 ) return -1;
-  rc = fseek(f, pos1, SEEK_SET);
-  if ( rc != 0 ) return -1;
-  return pos2 - pos1;
-}
-
-/*
-** Remove a managed file.  Update quotas accordingly.
-*/
-int sqlite3_quota_remove(const char *zFilename){
-  char *zFull;            /* Full pathname for zFilename */
-  size_t nFull;           /* Number of bytes in zFilename */
-  int rc;                 /* Result code */
-  quotaGroup *pGroup;     /* Group containing zFilename */
-  quotaFile *pFile;       /* A file in the group */
-  quotaFile *pNextFile;   /* next file in the group */
-  int diff;               /* Difference between filenames */
-  char c;                 /* First character past end of pattern */
-
-  zFull = (char*)sqlite3_malloc(gQuota.sThisVfs.mxPathname + 1);
-  if( zFull==0 ) return SQLITE_NOMEM;
-  rc = gQuota.pOrigVfs->xFullPathname(gQuota.pOrigVfs, zFilename,
-                                      gQuota.sThisVfs.mxPathname+1, zFull);
-  if( rc ){
-    sqlite3_free(zFull);
-    return rc;
-  }
-
-  /* Figure out the length of the full pathname.  If the name ends with
-  ** / (or \ on windows) then remove the trailing /.
-  */
-  nFull = strlen(zFull);
-  if( nFull>0 && (zFull[nFull-1]=='/' || zFull[nFull-1]=='\\') ){
-    nFull--;
-    zFull[nFull] = 0;
-  }
-
-  quotaEnter();
-  pGroup = quotaGroupFind(zFull);
-  if( pGroup ){
-    for(pFile=pGroup->pFiles; pFile && rc==SQLITE_OK; pFile=pNextFile){
-      pNextFile = pFile->pNext;
-      diff = memcmp(zFull, pFile->zFilename, nFull);
-      if( diff==0 && ((c = pFile->zFilename[nFull])==0 || c=='/' || c=='\\') ){
-        if( pFile->nRef ){
-          pFile->deleteOnClose = 1;
-        }else{
-          rc = gQuota.pOrigVfs->xDelete(gQuota.pOrigVfs, pFile->zFilename, 0);
-          quotaRemoveFile(pFile);
-          quotaGroupDeref(pGroup);
-        }
-      }
-    }
-  }
-  quotaLeave();
-  sqlite3_free(zFull);
-  return rc;
-}
-  
-/***************************** Test Code ***********************************/
-#ifdef SQLITE_TEST
-#include <tcl.h>
-
-/*
-** Argument passed to a TCL quota-over-limit callback.
-*/
-typedef struct TclQuotaCallback TclQuotaCallback;
-struct TclQuotaCallback {
-  Tcl_Interp *interp;    /* Interpreter in which to run the script */
-  Tcl_Obj *pScript;      /* Script to be run */
-};
-
-extern const char *sqlite3TestErrorName(int);
-
-
-/*
-** This is the callback from a quota-over-limit.
-*/
-static void tclQuotaCallback(
-  const char *zFilename,          /* Name of file whose size increases */
-  sqlite3_int64 *piLimit,         /* IN/OUT: The current limit */
-  sqlite3_int64 iSize,            /* Total size of all files in the group */
-  void *pArg                      /* Client data */
-){
-  TclQuotaCallback *p;            /* Callback script object */
-  Tcl_Obj *pEval;                 /* Script to evaluate */
-  Tcl_Obj *pVarname;              /* Name of variable to pass as 2nd arg */
-  unsigned int rnd;               /* Random part of pVarname */
-  int rc;                         /* Tcl error code */
-
-  p = (TclQuotaCallback *)pArg;
-  if( p==0 ) return;
-
-  pVarname = Tcl_NewStringObj("::piLimit_", -1);
-  Tcl_IncrRefCount(pVarname);
-  sqlite3_randomness(sizeof(rnd), (void *)&rnd);
-  Tcl_AppendObjToObj(pVarname, Tcl_NewIntObj((int)(rnd&0x7FFFFFFF)));
-  Tcl_ObjSetVar2(p->interp, pVarname, 0, Tcl_NewWideIntObj(*piLimit), 0);
-
-  pEval = Tcl_DuplicateObj(p->pScript);
-  Tcl_IncrRefCount(pEval);
-  Tcl_ListObjAppendElement(0, pEval, Tcl_NewStringObj(zFilename, -1));
-  Tcl_ListObjAppendElement(0, pEval, pVarname);
-  Tcl_ListObjAppendElement(0, pEval, Tcl_NewWideIntObj(iSize));
-  rc = Tcl_EvalObjEx(p->interp, pEval, TCL_EVAL_GLOBAL);
-
-  if( rc==TCL_OK ){
-    Tcl_Obj *pLimit = Tcl_ObjGetVar2(p->interp, pVarname, 0, 0);
-    rc = Tcl_GetWideIntFromObj(p->interp, pLimit, piLimit);
-    Tcl_UnsetVar(p->interp, Tcl_GetString(pVarname), 0);
-  }
-
-  Tcl_DecrRefCount(pEval);
-  Tcl_DecrRefCount(pVarname);
-  if( rc!=TCL_OK ) Tcl_BackgroundError(p->interp);
-}
-
-/*
-** Destructor for a TCL quota-over-limit callback.
-*/
-static void tclCallbackDestructor(void *pObj){
-  TclQuotaCallback *p = (TclQuotaCallback*)pObj;
-  if( p ){
-    Tcl_DecrRefCount(p->pScript);
-    sqlite3_free((char *)p);
-  }
-}
-
-/*
-** tclcmd: sqlite3_quota_initialize NAME MAKEDEFAULT
-*/
-static int test_quota_initialize(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  const char *zName;              /* Name of new quota VFS */
-  int makeDefault;                /* True to make the new VFS the default */
-  int rc;                         /* Value returned by quota_initialize() */
-
-  /* Process arguments */
-  if( objc!=3 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "NAME MAKEDEFAULT");
-    return TCL_ERROR;
-  }
-  zName = Tcl_GetString(objv[1]);
-  if( Tcl_GetBooleanFromObj(interp, objv[2], &makeDefault) ) return TCL_ERROR;
-  if( zName[0]=='\0' ) zName = 0;
-
-  /* Call sqlite3_quota_initialize() */
-  rc = sqlite3_quota_initialize(zName, makeDefault);
-  Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
-
-  return TCL_OK;
-}
-
-/*
-** tclcmd: sqlite3_quota_shutdown
-*/
-static int test_quota_shutdown(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  int rc;                         /* Value returned by quota_shutdown() */
-
-  if( objc!=1 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "");
-    return TCL_ERROR;
-  }
-
-  /* Call sqlite3_quota_shutdown() */
-  rc = sqlite3_quota_shutdown();
-  Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
-
-  return TCL_OK;
-}
-
-/*
-** tclcmd: sqlite3_quota_set PATTERN LIMIT SCRIPT
-*/
-static int test_quota_set(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  const char *zPattern;           /* File pattern to configure */
-  sqlite3_int64 iLimit;           /* Initial quota in bytes */
-  Tcl_Obj *pScript;               /* Tcl script to invoke to increase quota */
-  int rc;                         /* Value returned by quota_set() */
-  TclQuotaCallback *p;            /* Callback object */
-  int nScript;                    /* Length of callback script */
-  void (*xDestroy)(void*);        /* Optional destructor for pArg */
-  void (*xCallback)(const char *, sqlite3_int64 *, sqlite3_int64, void *);
-
-  /* Process arguments */
-  if( objc!=4 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "PATTERN LIMIT SCRIPT");
-    return TCL_ERROR;
-  }
-  zPattern = Tcl_GetString(objv[1]);
-  if( Tcl_GetWideIntFromObj(interp, objv[2], &iLimit) ) return TCL_ERROR;
-  pScript = objv[3];
-  Tcl_GetStringFromObj(pScript, &nScript);
-
-  if( nScript>0 ){
-    /* Allocate a TclQuotaCallback object */
-    p = (TclQuotaCallback *)sqlite3_malloc(sizeof(TclQuotaCallback));
-    if( !p ){
-      Tcl_SetResult(interp, (char *)"SQLITE_NOMEM", TCL_STATIC);
-      return TCL_OK;
-    }
-    memset(p, 0, sizeof(TclQuotaCallback));
-    p->interp = interp;
-    Tcl_IncrRefCount(pScript);
-    p->pScript = pScript;
-    xDestroy = tclCallbackDestructor;
-    xCallback = tclQuotaCallback;
-  }else{
-    p = 0;
-    xDestroy = 0;
-    xCallback = 0;
-  }
-
-  /* Invoke sqlite3_quota_set() */
-  rc = sqlite3_quota_set(zPattern, iLimit, xCallback, (void*)p, xDestroy);
-
-  Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
-  return TCL_OK;
-}
-
-/*
-** tclcmd: sqlite3_quota_file FILENAME
-*/
-static int test_quota_file(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  const char *zFilename;          /* File pattern to configure */
-  int rc;                         /* Value returned by quota_file() */
-
-  /* Process arguments */
-  if( objc!=2 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
-    return TCL_ERROR;
-  }
-  zFilename = Tcl_GetString(objv[1]);
-
-  /* Invoke sqlite3_quota_file() */
-  rc = sqlite3_quota_file(zFilename);
-
-  Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
-  return TCL_OK;
-}
-
-/*
-** tclcmd:  sqlite3_quota_dump
-*/
-static int test_quota_dump(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  Tcl_Obj *pResult;
-  Tcl_Obj *pGroupTerm;
-  Tcl_Obj *pFileTerm;
-  quotaGroup *pGroup;
-  quotaFile *pFile;
-
-  pResult = Tcl_NewObj();
-  quotaEnter();
-  for(pGroup=gQuota.pGroup; pGroup; pGroup=pGroup->pNext){
-    pGroupTerm = Tcl_NewObj();
-    Tcl_ListObjAppendElement(interp, pGroupTerm,
-          Tcl_NewStringObj(pGroup->zPattern, -1));
-    Tcl_ListObjAppendElement(interp, pGroupTerm,
-          Tcl_NewWideIntObj(pGroup->iLimit));
-    Tcl_ListObjAppendElement(interp, pGroupTerm,
-          Tcl_NewWideIntObj(pGroup->iSize));
-    for(pFile=pGroup->pFiles; pFile; pFile=pFile->pNext){
-      int i;
-      char zTemp[1000];
-      pFileTerm = Tcl_NewObj();
-      sqlite3_snprintf(sizeof(zTemp), zTemp, "%s", pFile->zFilename);
-      for(i=0; zTemp[i]; i++){ if( zTemp[i]=='\\' ) zTemp[i] = '/'; }
-      Tcl_ListObjAppendElement(interp, pFileTerm,
-            Tcl_NewStringObj(zTemp, -1));
-      Tcl_ListObjAppendElement(interp, pFileTerm,
-            Tcl_NewWideIntObj(pFile->iSize));
-      Tcl_ListObjAppendElement(interp, pFileTerm,
-            Tcl_NewWideIntObj(pFile->nRef));
-      Tcl_ListObjAppendElement(interp, pFileTerm,
-            Tcl_NewWideIntObj(pFile->deleteOnClose));
-      Tcl_ListObjAppendElement(interp, pGroupTerm, pFileTerm);
-    }
-    Tcl_ListObjAppendElement(interp, pResult, pGroupTerm);
-  }
-  quotaLeave();
-  Tcl_SetObjResult(interp, pResult);
-  return TCL_OK;
-}
-
-/*
-** tclcmd: sqlite3_quota_fopen FILENAME MODE
-*/
-static int test_quota_fopen(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  const char *zFilename;          /* File pattern to configure */
-  const char *zMode;              /* Mode string */
-  quota_FILE *p;                  /* Open string object */
-  char zReturn[50];               /* Name of pointer to return */
-
-  /* Process arguments */
-  if( objc!=3 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "FILENAME MODE");
-    return TCL_ERROR;
-  }
-  zFilename = Tcl_GetString(objv[1]);
-  zMode = Tcl_GetString(objv[2]);
-  p = sqlite3_quota_fopen(zFilename, zMode);
-  sqlite3_snprintf(sizeof(zReturn), zReturn, "%p", p);
-  Tcl_SetResult(interp, zReturn, TCL_VOLATILE);
-  return TCL_OK;
-}
-
-/* Defined in test1.c */
-extern void *sqlite3TestTextToPtr(const char*);
-
-/*
-** tclcmd: sqlite3_quota_fread HANDLE SIZE NELEM
-*/
-static int test_quota_fread(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  quota_FILE *p;
-  char *zBuf;
-  int sz;
-  int nElem;
-  size_t got;
-
-  if( objc!=4 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE SIZE NELEM");
-    return TCL_ERROR;
-  }
-  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
-  if( Tcl_GetIntFromObj(interp, objv[2], &sz) ) return TCL_ERROR;
-  if( Tcl_GetIntFromObj(interp, objv[3], &nElem) ) return TCL_ERROR;
-  zBuf = (char*)sqlite3_malloc( sz*nElem + 1 );
-  if( zBuf==0 ){
-    Tcl_SetResult(interp, "out of memory", TCL_STATIC);
-    return TCL_ERROR;
-  }
-  got = sqlite3_quota_fread(zBuf, sz, nElem, p);
-  if( got<0 ) got = 0;
-  zBuf[got*sz] = 0;
-  Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
-  sqlite3_free(zBuf);
-  return TCL_OK;
-}
-
-/*
-** tclcmd: sqlite3_quota_fwrite HANDLE SIZE NELEM CONTENT
-*/
-static int test_quota_fwrite(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  quota_FILE *p;
-  char *zBuf;
-  int sz;
-  int nElem;
-  size_t got;
-
-  if( objc!=5 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE SIZE NELEM CONTENT");
-    return TCL_ERROR;
-  }
-  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
-  if( Tcl_GetIntFromObj(interp, objv[2], &sz) ) return TCL_ERROR;
-  if( Tcl_GetIntFromObj(interp, objv[3], &nElem) ) return TCL_ERROR;
-  zBuf = Tcl_GetString(objv[4]);
-  got = sqlite3_quota_fwrite(zBuf, sz, nElem, p);
-  Tcl_SetObjResult(interp, Tcl_NewWideIntObj(got));
-  return TCL_OK;
-}
-
-/*
-** tclcmd: sqlite3_quota_fclose HANDLE
-*/
-static int test_quota_fclose(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  quota_FILE *p;
-  int rc;
-
-  if( objc!=2 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
-    return TCL_ERROR;
-  }
-  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
-  rc = sqlite3_quota_fclose(p);
-  Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
-  return TCL_OK;
-}
-
-/*
-** tclcmd: sqlite3_quota_fflush HANDLE ?HARDSYNC?
-*/
-static int test_quota_fflush(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  quota_FILE *p;
-  int rc;
-  int doSync = 0;
-
-  if( objc!=2 && objc!=3 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE ?HARDSYNC?");
-    return TCL_ERROR;
-  }
-  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
-  if( objc==3 ){
-    if( Tcl_GetBooleanFromObj(interp, objv[2], &doSync) ) return TCL_ERROR;
-  }
-  rc = sqlite3_quota_fflush(p, doSync);
-  Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
-  return TCL_OK;
-}
-
-/*
-** tclcmd: sqlite3_quota_fseek HANDLE OFFSET WHENCE
-*/
-static int test_quota_fseek(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  quota_FILE *p;
-  int ofst;
-  const char *zWhence;
-  int whence;
-  int rc;
-
-  if( objc!=4 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE OFFSET WHENCE");
-    return TCL_ERROR;
-  }
-  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
-  if( Tcl_GetIntFromObj(interp, objv[2], &ofst) ) return TCL_ERROR;
-  zWhence = Tcl_GetString(objv[3]);
-  if( strcmp(zWhence, "SEEK_SET")==0 ){
-    whence = SEEK_SET;
-  }else if( strcmp(zWhence, "SEEK_CUR")==0 ){
-    whence = SEEK_CUR;
-  }else if( strcmp(zWhence, "SEEK_END")==0 ){
-    whence = SEEK_END;
-  }else{
-    Tcl_AppendResult(interp,
-           "WHENCE should be SEEK_SET, SEEK_CUR, or SEEK_END", (char*)0);
-    return TCL_ERROR;
-  }
-  rc = sqlite3_quota_fseek(p, ofst, whence);
-  Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
-  return TCL_OK;
-}
-
-/*
-** tclcmd: sqlite3_quota_rewind HANDLE
-*/
-static int test_quota_rewind(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  quota_FILE *p;
-  if( objc!=2 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
-    return TCL_ERROR;
-  }
-  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
-  sqlite3_quota_rewind(p);
-  return TCL_OK;
-}
-
-/*
-** tclcmd: sqlite3_quota_ftell HANDLE
-*/
-static int test_quota_ftell(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  quota_FILE *p;
-  sqlite3_int64 x;
-  if( objc!=2 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
-    return TCL_ERROR;
-  }
-  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
-  x = sqlite3_quota_ftell(p);
-  Tcl_SetObjResult(interp, Tcl_NewWideIntObj(x));
-  return TCL_OK;
-}
-
-/*
-** tclcmd: sqlite3_quota_ftruncate HANDLE SIZE
-*/
-static int test_quota_ftruncate(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  quota_FILE *p;
-  sqlite3_int64 x;
-  Tcl_WideInt w;
-  int rc;
-  if( objc!=3 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE SIZE");
-    return TCL_ERROR;
-  }
-  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
-  if( Tcl_GetWideIntFromObj(interp, objv[2], &w) ) return TCL_ERROR;
-  x = (sqlite3_int64)w;
-  rc = sqlite3_quota_ftruncate(p, x);
-  Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
-  return TCL_OK;
-}
-
-/*
-** tclcmd: sqlite3_quota_file_size HANDLE
-*/
-static int test_quota_file_size(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  quota_FILE *p;
-  sqlite3_int64 x;
-  if( objc!=2 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
-    return TCL_ERROR;
-  }
-  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
-  x = sqlite3_quota_file_size(p);
-  Tcl_SetObjResult(interp, Tcl_NewWideIntObj(x));
-  return TCL_OK;
-}
-
-/*
-** tclcmd: sqlite3_quota_file_truesize HANDLE
-*/
-static int test_quota_file_truesize(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  quota_FILE *p;
-  sqlite3_int64 x;
-  if( objc!=2 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
-    return TCL_ERROR;
-  }
-  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
-  x = sqlite3_quota_file_truesize(p);
-  Tcl_SetObjResult(interp, Tcl_NewWideIntObj(x));
-  return TCL_OK;
-}
-
-/*
-** tclcmd: sqlite3_quota_file_mtime HANDLE
-*/
-static int test_quota_file_mtime(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  quota_FILE *p;
-  time_t t;
-  if( objc!=2 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
-    return TCL_ERROR;
-  }
-  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
-  t = 0;
-  sqlite3_quota_file_mtime(p, &t);
-  Tcl_SetObjResult(interp, Tcl_NewWideIntObj(t));
-  return TCL_OK;
-}
-
-
-/*
-** tclcmd: sqlite3_quota_remove FILENAME
-*/
-static int test_quota_remove(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  const char *zFilename;          /* File pattern to configure */
-  int rc;
-  if( objc!=2 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
-    return TCL_ERROR;
-  }
-  zFilename = Tcl_GetString(objv[1]);
-  rc = sqlite3_quota_remove(zFilename);
-  Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
-  return TCL_OK;
-}
-
-/*
-** tclcmd: sqlite3_quota_glob PATTERN TEXT
-**
-** Test the glob pattern matching.  Return 1 if TEXT matches PATTERN
-** and return 0 if it does not.
-*/
-static int test_quota_glob(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  const char *zPattern;          /* The glob pattern */
-  const char *zText;             /* Text to compare agains the pattern */
-  int rc;
-  if( objc!=3 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "PATTERN TEXT");
-    return TCL_ERROR;
-  }
-  zPattern = Tcl_GetString(objv[1]);
-  zText = Tcl_GetString(objv[2]);
-  rc = quotaStrglob(zPattern, zText);
-  Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
-  return TCL_OK;
-}
-
-/*
-** tclcmd: sqlite3_quota_file_available HANDLE
-**
-** Return the number of bytes from the current file point to the end of
-** the file.
-*/
-static int test_quota_file_available(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  quota_FILE *p;
-  sqlite3_int64 x;
-  if( objc!=2 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
-    return TCL_ERROR;
-  }
-  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
-  x = sqlite3_quota_file_available(p);
-  Tcl_SetObjResult(interp, Tcl_NewWideIntObj(x));
-  return TCL_OK;
-}
-
-/*
-** tclcmd: sqlite3_quota_ferror HANDLE
-**
-** Return true if the file handle is in the error state.
-*/
-static int test_quota_ferror(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  quota_FILE *p;
-  int x;
-  if( objc!=2 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
-    return TCL_ERROR;
-  }
-  p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
-  x = sqlite3_quota_ferror(p);
-  Tcl_SetObjResult(interp, Tcl_NewIntObj(x));
-  return TCL_OK;
-}
-
-/*
-** This routine registers the custom TCL commands defined in this
-** module.  This should be the only procedure visible from outside
-** of this module.
-*/
-int Sqlitequota_Init(Tcl_Interp *interp){
-  static struct {
-     char *zName;
-     Tcl_ObjCmdProc *xProc;
-  } aCmd[] = {
-    { "sqlite3_quota_initialize",    test_quota_initialize },
-    { "sqlite3_quota_shutdown",      test_quota_shutdown },
-    { "sqlite3_quota_set",           test_quota_set },
-    { "sqlite3_quota_file",          test_quota_file },
-    { "sqlite3_quota_dump",          test_quota_dump },
-    { "sqlite3_quota_fopen",         test_quota_fopen },
-    { "sqlite3_quota_fread",         test_quota_fread },
-    { "sqlite3_quota_fwrite",        test_quota_fwrite },
-    { "sqlite3_quota_fclose",        test_quota_fclose },
-    { "sqlite3_quota_fflush",        test_quota_fflush },
-    { "sqlite3_quota_fseek",         test_quota_fseek },
-    { "sqlite3_quota_rewind",        test_quota_rewind },
-    { "sqlite3_quota_ftell",         test_quota_ftell },
-    { "sqlite3_quota_ftruncate",     test_quota_ftruncate },
-    { "sqlite3_quota_file_size",     test_quota_file_size },
-    { "sqlite3_quota_file_truesize", test_quota_file_truesize },
-    { "sqlite3_quota_file_mtime",    test_quota_file_mtime },
-    { "sqlite3_quota_remove",        test_quota_remove },
-    { "sqlite3_quota_glob",          test_quota_glob },
-    { "sqlite3_quota_file_available",test_quota_file_available },
-    { "sqlite3_quota_ferror",        test_quota_ferror },
-  };
-  int i;
-
-  for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
-    Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
-  }
-
-  return TCL_OK;
-}
-#endif
deleted file mode 100644
--- a/db/sqlite3/src/test_quota.h
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
-** 2011 December 1
-**
-** The author disclaims copyright to this source code.  In place of
-** a legal notice, here is a blessing:
-**
-**    May you do good and not evil.
-**    May you find forgiveness for yourself and forgive others.
-**    May you share freely, never taking more than you give.
-**
-*************************************************************************
-**
-** This file contains the interface definition for the quota a VFS shim.
-**
-** This particular shim enforces a quota system on files.  One or more
-** database files are in a "quota group" that is defined by a GLOB
-** pattern.  A quota is set for the combined size of all files in the
-** the group.  A quota of zero means "no limit".  If the total size
-** of all files in the quota group is greater than the limit, then
-** write requests that attempt to enlarge a file fail with SQLITE_FULL.
-**
-** However, before returning SQLITE_FULL, the write requests invoke
-** a callback function that is configurable for each quota group.
-** This callback has the opportunity to enlarge the quota.  If the
-** callback does enlarge the quota such that the total size of all
-** files within the group is less than the new quota, then the write
-** continues as if nothing had happened.
-*/
-#ifndef _QUOTA_H_
-#include "sqlite3.h"
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#if SQLITE_OS_UNIX
-# include <unistd.h>
-#endif
-#if SQLITE_OS_WIN
-# include <windows.h>
-#endif
-
-/* Make this callable from C++ */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
-** Initialize the quota VFS shim.  Use the VFS named zOrigVfsName
-** as the VFS that does the actual work.  Use the default if
-** zOrigVfsName==NULL.  
-**
-** The quota VFS shim is named "quota".  It will become the default
-** VFS if makeDefault is non-zero.
-**
-** THIS ROUTINE IS NOT THREADSAFE.  Call this routine exactly once
-** during start-up.
-*/
-int sqlite3_quota_initialize(const char *zOrigVfsName, int makeDefault);
-
-/*
-** Shutdown the quota system.
-**
-** All SQLite database connections must be closed before calling this
-** routine.
-**
-** THIS ROUTINE IS NOT THREADSAFE.  Call this routine exactly once while
-** shutting down in order to free all remaining quota groups.
-*/
-int sqlite3_quota_shutdown(void);
-
-/*
-** Create or destroy a quota group.
-**
-** The quota group is defined by the zPattern.  When calling this routine
-** with a zPattern for a quota group that already exists, this routine
-** merely updates the iLimit, xCallback, and pArg values for that quota
-** group.  If zPattern is new, then a new quota group is created.
-**
-** The zPattern is always compared against the full pathname of the file.
-** Even if APIs are called with relative pathnames, SQLite converts the
-** name to a full pathname before comparing it against zPattern.  zPattern
-** is a glob pattern with the following matching rules:
-**
-**      '*'       Matches any sequence of zero or more characters.
-**
-**      '?'       Matches exactly one character.
-**
-**     [...]      Matches one character from the enclosed list of
-**                characters.  "]" can be part of the list if it is
-**                the first character.  Within the list "X-Y" matches
-**                characters X or Y or any character in between the
-**                two.  Ex:  "[0-9]" matches any digit.
-**
-**     [^...]     Matches one character not in the enclosed list.
-**
-**     /          Matches either / or \.  This allows glob patterns
-**                containing / to work on both unix and windows.
-**
-** Note that, unlike unix shell globbing, the directory separator "/"
-** can match a wildcard.  So, for example, the pattern "/abc/xyz/" "*"
-** matches any files anywhere in the directory hierarchy beneath
-** /abc/xyz.
-**
-** The glob algorithm works on bytes.  Multi-byte UTF8 characters are
-** matched as if each byte were a separate character.
-**
-** If the iLimit for a quota group is set to zero, then the quota group
-** is disabled and will be deleted when the last database connection using
-** the quota group is closed.
-**
-** Calling this routine on a zPattern that does not exist and with a
-** zero iLimit is a no-op.
-**
-** A quota group must exist with a non-zero iLimit prior to opening
-** database connections if those connections are to participate in the
-** quota group.  Creating a quota group does not affect database connections
-** that are already open.
-**
-** The patterns that define the various quota groups should be distinct.
-** If the same filename matches more than one quota group pattern, then
-** the behavior of this package is undefined.
-*/
-int sqlite3_quota_set(
-  const char *zPattern,           /* The filename pattern */
-  sqlite3_int64 iLimit,           /* New quota to set for this quota group */
-  void (*xCallback)(              /* Callback invoked when going over quota */
-     const char *zFilename,         /* Name of file whose size increases */
-     sqlite3_int64 *piLimit,        /* IN/OUT: The current limit */
-     sqlite3_int64 iSize,           /* Total size of all files in the group */
-     void *pArg                     /* Client data */
-  ),
-  void *pArg,                     /* client data passed thru to callback */
-  void (*xDestroy)(void*)         /* Optional destructor for pArg */
-);
-
-/*
-** Bring the named file under quota management, assuming its name matches
-** the glob pattern of some quota group.  Or if it is already under
-** management, update its size.  If zFilename does not match the glob
-** pattern of any quota group, this routine is a no-op.
-*/
-int sqlite3_quota_file(const char *zFilename);
-
-/*
-** The following object serves the same role as FILE in the standard C
-** library.  It represents an open connection to a file on disk for I/O.
-**
-** A single quota_FILE should not be used by two or more threads at the
-** same time.  Multiple threads can be using different quota_FILE objects
-** simultaneously, but not the same quota_FILE object.
-*/
-typedef struct quota_FILE quota_FILE;
-
-/*
-** Create a new quota_FILE object used to read and/or write to the
-** file zFilename.  The zMode parameter is as with standard library zMode.
-*/
-quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode);
-
-/*
-** Perform I/O against a quota_FILE object.  When doing writes, the
-** quota mechanism may result in a short write, in order to prevent
-** the sum of sizes of all files from going over quota.
-*/
-size_t sqlite3_quota_fread(void*, size_t, size_t, quota_FILE*);
-size_t sqlite3_quota_fwrite(const void*, size_t, size_t, quota_FILE*);
-
-/*
-** Flush all written content held in memory buffers out to disk.
-** This is the equivalent of fflush() in the standard library.
-**
-** If the hardSync parameter is true (non-zero) then this routine
-** also forces OS buffers to disk - the equivalent of fsync().
-**
-** This routine return zero on success and non-zero if something goes
-** wrong.
-*/
-int sqlite3_quota_fflush(quota_FILE*, int hardSync);
-
-/*
-** Close a quota_FILE object and free all associated resources.  The
-** file remains under quota management.
-*/
-int sqlite3_quota_fclose(quota_FILE*);
-
-/*
-** Move the read/write pointer for a quota_FILE object.  Or tell the
-** current location of the read/write pointer.
-*/
-int sqlite3_quota_fseek(quota_FILE*, long, int);
-void sqlite3_quota_rewind(quota_FILE*);
-long sqlite3_quota_ftell(quota_FILE*);
-
-/*
-** Test the error indicator for the given file.
-**
-** Return non-zero if the error indicator is set.
-*/
-int sqlite3_quota_ferror(quota_FILE*);
-
-/*
-** Truncate a file previously opened by sqlite3_quota_fopen().  Return
-** zero on success and non-zero on any kind of failure.
-**
-** The newSize argument must be less than or equal to the current file size.
-** Any attempt to "truncate" a file to a larger size results in 
-** undefined behavior.
-*/
-int sqlite3_quota_ftruncate(quota_FILE*, sqlite3_int64 newSize);
-
-/*
-** Return the last modification time of the opened file, in seconds
-** since 1970.
-*/
-int sqlite3_quota_file_mtime(quota_FILE*, time_t *pTime);
-
-/*
-** Return the size of the file as it is known to the quota system.
-**
-** This size might be different from the true size of the file on
-** disk if some outside process has modified the file without using the
-** quota mechanism, or if calls to sqlite3_quota_fwrite() have occurred
-** which have increased the file size, but those writes have not yet been
-** forced to disk using sqlite3_quota_fflush().
-**
-** Return -1 if the file is not participating in quota management.
-*/
-sqlite3_int64 sqlite3_quota_file_size(quota_FILE*);
-
-/*
-** Return the true size of the file.
-**
-** The true size should be the same as the size of the file as known
-** to the quota system, however the sizes might be different if the
-** file has been extended or truncated via some outside process or if
-** pending writes have not yet been flushed to disk.
-**
-** Return -1 if the file does not exist or if the size of the file
-** cannot be determined for some reason.
-*/
-sqlite3_int64 sqlite3_quota_file_truesize(quota_FILE*);
-
-/*
-** Determine the amount of data in bytes available for reading
-** in the given file.
-**
-** Return -1 if the amount cannot be determined for some reason.
-*/
-long sqlite3_quota_file_available(quota_FILE*);
-
-/*
-** Delete a file from the disk, if that file is under quota management.
-** Adjust quotas accordingly.
-**
-** If zFilename is the name of a directory that matches one of the
-** quota glob patterns, then all files under quota management that
-** are contained within that directory are deleted.
-**
-** A standard SQLite result code is returned (SQLITE_OK, SQLITE_NOMEM, etc.)
-** When deleting a directory of files, if the deletion of any one
-** file fails (for example due to an I/O error), then this routine
-** returns immediately, with the error code, and does not try to 
-** delete any of the other files in the specified directory.
-**
-** All files are removed from quota management and deleted from disk.
-** However, no attempt is made to remove empty directories.
-**
-** This routine is a no-op for files that are not under quota management.
-*/
-int sqlite3_quota_remove(const char *zFilename);
-
-#ifdef __cplusplus
-}  /* end of the 'extern "C"' block */
-#endif
-#endif /* _QUOTA_H_ */
--- a/dom/Makefile.in
+++ b/dom/Makefile.in
@@ -53,16 +53,17 @@ PARALLEL_DIRS += \
   phonenumberutils \
   alarm \
   devicestorage \
   encoding \
   file \
   media \
   messages \
   power \
+  quota \
   settings \
   sms \
   mms \
   src \
   time \
   locales \
   network \
   permission \
--- a/dom/dom-config.mk
+++ b/dom/dom-config.mk
@@ -3,16 +3,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DOM_SRCDIRS = \
   dom/base \
   dom/battery \
   dom/encoding \
   dom/file \
   dom/power \
+  dom/quota \
   dom/media \
   dom/network/src \
   dom/settings \
   dom/phonenumberutils \
   dom/sms/src \
   dom/contacts \
   dom/permission \
   dom/alarm \
--- a/dom/file/FileStreamWrappers.cpp
+++ b/dom/file/FileStreamWrappers.cpp
@@ -3,17 +3,16 @@
 /* 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 "FileStreamWrappers.h"
 
 #include "nsIFileStorage.h"
 #include "nsISeekableStream.h"
-#include "nsIStandardFileStream.h"
 #include "mozilla/Attributes.h"
 
 #include "FileHelper.h"
 
 USING_FILE_NAMESPACE
 
 namespace {
 
@@ -241,26 +240,16 @@ NS_IMPL_ISUPPORTS_INHERITED1(FileOutputS
 NS_IMETHODIMP
 FileOutputStreamWrapper::Close()
 {
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
   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();
   }
 
   if (mFlags & NOTIFY_CLOSE) {
     nsCOMPtr<nsIRunnable> runnable = new CloseRunnable(mFileHelper);
 
--- a/dom/file/LockedFile.cpp
+++ b/dom/file/LockedFile.cpp
@@ -948,30 +948,30 @@ FinishHelper::Run()
   }
 
   nsIFileStorage* fileStorage = mLockedFile->mFileHandle->mFileStorage;
   if (fileStorage->IsStorageInvalidated()) {
     mAborted = true;
   }
 
   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!");
     }
 
     mParallelStreams[index] = nullptr;
   }
 
   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!");
     }
 
     mStream = nullptr;
   }
 
   return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
 }
--- a/dom/file/nsIFileStorage.h
+++ b/dom/file/nsIFileStorage.h
@@ -5,24 +5,27 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsIFileStorage_h__
 #define nsIFileStorage_h__
 
 #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;
 
   virtual bool
   IsStorageInvalidated() = 0;
 
   virtual bool
   IsStorageShuttingDown() = 0;
@@ -31,25 +34,28 @@ public:
   SetThreadLocals() = 0;
 
   virtual void
   UnsetThreadLocals() = 0;
 };
 
 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__
--- a/dom/indexedDB/FileManager.cpp
+++ b/dom/indexedDB/FileManager.cpp
@@ -2,27 +2,29 @@
 /* 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 "FileManager.h"
 
 #include "mozIStorageConnection.h"
-#include "mozIStorageServiceQuotaManagement.h"
 #include "mozIStorageStatement.h"
+#include "nsIInputStream.h"
 #include "nsISimpleEnumerator.h"
 
 #include "mozStorageCID.h"
 #include "mozStorageHelper.h"
 
 #include "FileInfo.h"
 #include "IndexedDatabaseManager.h"
 #include "OpenDatabaseHelper.h"
 
+#include "IndexedDatabaseInlines.h"
+
 #define JOURNAL_DIRECTORY_NAME "journals"
 
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
 PLDHashOperator
 EnumerateToTArray(const uint64_t& aKey,
@@ -257,23 +259,21 @@ FileManager::GetFileForId(nsIFile* aDire
   rv = file->Append(id);
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   return file.forget();
 }
 
 // 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!");
 
   bool exists;
   nsresult rv = aDirectory->Exists(&exists);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!exists) {
@@ -305,18 +305,18 @@ FileManager::InitDirectory(mozIStorageSe
     NS_ENSURE_SUCCESS(rv, rv);
 
     bool hasElements;
     rv = entries->HasMoreElements(&hasElements);
     NS_ENSURE_SUCCESS(rv, rv);
 
     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);
 
       rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
         "CREATE VIRTUAL TABLE fs USING filesystem;"
       ));
       NS_ENSURE_SUCCESS(rv, rv);
@@ -372,22 +372,27 @@ FileManager::InitDirectory(mozIStorageSe
         "DROP TABLE fs;"
       ));
       NS_ENSURE_SUCCESS(rv, rv);
 
       transaction.Commit();
     }
   }
 
-  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;
   while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
     nsCOMPtr<nsISupports> entry;
     rv = entries->GetNext(getter_AddRefs(entry));
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -397,14 +402,18 @@ FileManager::InitDirectory(mozIStorageSe
     nsString leafName;
     rv = file->GetLeafName(leafName);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (leafName.EqualsLiteral(JOURNAL_DIRECTORY_NAME)) {
       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;
 }
--- a/dom/indexedDB/FileManager.h
+++ b/dom/indexedDB/FileManager.h
@@ -19,32 +19,37 @@ BEGIN_INDEXEDDB_NAMESPACE
 
 class FileInfo;
 
 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()
   { }
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FileManager)
 
   const nsACString& Origin() const
   {
     return mOrigin;
   }
 
+  const FactoryPrivilege& Privilege() const
+  {
+    return mPrivilege;
+  }
+
   const nsAString& DatabaseName() const
   {
     return mDatabaseName;
   }
 
   bool Invalidated() const
   {
     return mInvalidated;
@@ -63,22 +68,25 @@ public:
 
   already_AddRefed<FileInfo> GetFileInfo(int64_t aId);
 
   already_AddRefed<FileInfo> GetNewFileInfo();
 
   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;
   nsString mJournalDirectoryPath;
 
   int64_t mLastFileId;
 
   // Protected by IndexedDatabaseManager::FileMutex()
deleted file mode 100644
--- a/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;
-}
deleted file mode 100644
--- a/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__
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -774,16 +774,22 @@ IDBDatabase::Close()
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   CloseInternal(false);
 
   NS_ASSERTION(mClosed, "Should have set the closed flag!");
   return NS_OK;
 }
 
+const nsACString&
+IDBDatabase::StorageOrigin()
+{
+  return Origin();
+}
+
 nsISupports*
 IDBDatabase::StorageId()
 {
   return Id();
 }
 
 bool
 IDBDatabase::IsStorageInvalidated()
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -248,41 +248,61 @@ IDBFactory::Create(ContentParent* aConte
   NS_HOLD_JS_OBJECTS(factory, IDBFactory);
   factory->mRootedOwningObject = true;
 
   factory.forget(aFactory);
   return NS_OK;
 }
 
 // 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")),
                "Bad file path!");
 
   nsCOMPtr<nsIFile> dbFile(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
   NS_ENSURE_TRUE(dbFile, nullptr);
 
   nsresult rv = dbFile->InitWithPath(aDatabaseFilePath);
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   bool exists;
   rv = dbFile->Exists(&exists);
   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.
   // The "INSERT OR REPLACE" statement doesn't fire the update trigger,
   // instead it fires only the insert trigger. This confuses the update
   // refcount function. This behavior changes with enabled recursive triggers,
   // so the statement fires the delete trigger first and then the insert
   // trigger.
--- a/dom/indexedDB/IDBFactory.h
+++ b/dom/indexedDB/IDBFactory.h
@@ -10,16 +10,18 @@
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
 
 #include "mozIStorageConnection.h"
 #include "nsIIDBFactory.h"
 
 #include "nsCycleCollectionParticipant.h"
 
 class nsIAtom;
+class nsIFile;
+class nsIFileURL;
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 class ContentParent;
 }
 }
 
@@ -70,18 +72,22 @@ public:
                          ContentParent* aContentParent,
                          IDBFactory** aFactory);
 
   // Called when using IndexedDB from a JS component or a JSM in a different
   // process.
   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,
                           nsIAtom* aDatabaseId,
                           uint64_t* aVersion,
                           ObjectStoreInfoArray& aObjectStores);
 
   static nsresult
--- a/dom/indexedDB/IDBFileHandle.cpp
+++ b/dom/indexedDB/IDBFileHandle.cpp
@@ -1,25 +1,24 @@
 /* -*- 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 "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 {
 
 inline
 already_AddRefed<nsIFile>
 GetFileFor(FileInfo* aFileInfo)
 
 {
@@ -63,32 +62,32 @@ IDBFileHandle::Create(IDBDatabase* aData
   fileInfo.swap(newFile->mFileInfo);
 
   return newFile.forget();
 }
 
 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();
 }
 
 already_AddRefed<nsIDOMFile>
 IDBFileHandle::CreateFileObject(mozilla::dom::file::LockedFile* aLockedFile,
                                 uint32_t aFileSize)
 {
   nsCOMPtr<nsIDOMFile> file = new mozilla::dom::file::File(
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -12,30 +12,29 @@
 #include "nsIJSContextStack.h"
 #include "nsIOutputStream.h"
 
 #include "jsfriendapi.h"
 #include "mozilla/dom/ContentChild.h"
 #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"
 #include "nsDOMFile.h"
 #include "nsDOMLists.h"
 #include "nsEventDispatcher.h"
 #include "nsJSUtils.h"
 #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"
 #include "IDBIndex.h"
 #include "IDBKeyRange.h"
 #include "IDBTransaction.h"
 #include "DatabaseInfo.h"
 #include "DictionaryHelpers.h"
@@ -46,16 +45,17 @@
 
 #include "IndexedDatabaseInlines.h"
 
 #define FILE_COPY_BUFFER_SIZE 32768
 
 USING_INDEXEDDB_NAMESPACE
 using namespace mozilla::dom;
 using namespace mozilla::dom::indexedDB::ipc;
+using mozilla::dom::quota::FileOutputStream;
 
 namespace {
 
 inline
 bool
 IgnoreNothing(PRUnichar c)
 {
   return false;
@@ -2729,19 +2729,19 @@ AddHelper::DoDatabaseWork(mozIStorageCon
 
         rv = nativeFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
         NS_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
         // Now we can copy the blob
         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);
 
         cloneFile.mFile->AddFileInfo(fileInfo);
       }
 
       if (index) {
--- a/dom/indexedDB/IDBTransaction.cpp
+++ b/dom/indexedDB/IDBTransaction.cpp
@@ -347,17 +347,18 @@ IDBTransaction::GetOrCreateConnection(mo
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
   if (mDatabase->IsInvalidated()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   if (!mConnection) {
     nsCOMPtr<mozIStorageConnection> connection =
-      IDBFactory::GetConnection(mDatabase->FilePath());
+      IDBFactory::GetConnection(mDatabase->FilePath(),
+                                mDatabase->Origin());
     NS_ENSURE_TRUE(connection, NS_ERROR_FAILURE);
 
     nsresult rv;
 
     nsRefPtr<UpdateRefcountFunction> function;
     nsCString beginTransaction;
     if (mMode != IDBTransaction::READ_ONLY) {
       function = new UpdateRefcountFunction(Database()->Manager());
--- a/dom/indexedDB/IndexedDatabaseInlines.h
+++ b/dom/indexedDB/IndexedDatabaseInlines.h
@@ -74,9 +74,22 @@ AppendConditionClause(const nsACString& 
 
   if (aEquals) {
     aResult.AppendLiteral("=");
   }
 
   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
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -17,42 +17,44 @@
 #include "nsIScriptError.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsISHEntry.h"
 #include "nsISimpleEnumerator.h"
 #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"
 #include "mozilla/Services.h"
 #include "mozilla/storage.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsContentUtils.h"
 #include "nsCRTGlue.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsEventDispatcher.h"
 #include "nsScriptSecurityManager.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMPrivate.h"
-#include "test_quota.h"
 #include "xpcpublic.h"
 
 #include "AsyncConnectionHelper.h"
 #include "CheckQuotaHelper.h"
 #include "IDBDatabase.h"
 #include "IDBEvents.h"
 #include "IDBFactory.h"
 #include "IDBKeyRange.h"
 #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
 
 // The amount of time, in milliseconds, that we will wait for active database
 // transactions on shutdown before aborting them.
 #define DEFAULT_SHUTDOWN_TIMER_MS 30000
 
@@ -65,16 +67,17 @@
 // profile-before-change, when we need to shut down IDB
 #define PROFILE_BEFORE_CHANGE_OBSERVER_ID "profile-before-change"
 
 USING_INDEXEDDB_NAMESPACE
 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);
 
 namespace {
 
 int32_t gShutdown = 0;
 int32_t gClosed = 0;
 
@@ -98,39 +101,16 @@ GetDatabaseBaseFilename(const nsAString&
     return false;
   }
 
   aDatabaseBaseFilename = Substring(aFilename, 0, filenameLen - sqliteLen);
 
   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
 EnumerateToTArray(const nsACString& aKey,
                   nsTArray<IDBDatabase*>* aValue,
                   void* aUserArg)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@@ -435,18 +415,18 @@ IndexedDatabaseManager::GetOrCreate()
 
       // Make a lazy thread for any IO we need (like clearing or enumerating the
       // contents of indexedDB database directories).
       instance->mIOThread =
         new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
                            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.
       instance->mShutdownTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
       NS_ENSURE_TRUE(instance->mShutdownTimer, nullptr);
     }
 
     nsCOMPtr<nsIObserverService> obs = GetObserverService();
@@ -991,47 +971,25 @@ IndexedDatabaseManager::EnsureOriginIsIn
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (mInitializedOrigins.Contains(aOrigin)) {
     NS_ADDREF(*aDirectory = directory);
     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);
 
   nsCOMPtr<nsISimpleEnumerator> entries;
   rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasMore;
@@ -1063,30 +1021,38 @@ IndexedDatabaseManager::EnsureOriginIsIn
     }
 
     nsString dbBaseFilename;
     if (!GetDatabaseBaseFilename(leafName, dbBaseFilename)) {
       unknownFiles.AppendElement(file);
       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);
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   for (uint32_t i = 0; i < subdirsToProcess.Length(); i++) {
     const nsString& subdir = subdirsToProcess[i];
@@ -1112,22 +1078,49 @@ IndexedDatabaseManager::EnsureOriginIsIn
       // The journal file may exists even after db has been correctly opened.
       if (!StringEndsWith(leafName, NS_LITERAL_STRING(".sqlite-journal"))) {
         NS_WARNING("Unknown file found!");
         return NS_ERROR_UNEXPECTED;
       }
     }
   }
 
+  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()
 {
   nsPIDOMWindow* window = nullptr;
   nsRefPtr<CheckQuotaHelper> helper = nullptr;
   bool createdHelper = false;
 
   window =
@@ -1245,26 +1238,24 @@ IndexedDatabaseManager::GetFileManager(c
       return result.forget();
     }
   }
   
   return nullptr;
 }
 
 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);
 }
 
 void
 IndexedDatabaseManager::InvalidateFileManagersForPattern(
                                                      const nsACString& aPattern)
@@ -1778,16 +1769,23 @@ OriginClearRunnable::DeleteFiles(Indexed
       continue;
     }
 
     if (NS_FAILED(file->Remove(true))) {
       // This should never fail if we've closed all database connections
       // correctly...
       NS_ERROR("Failed to remove directory!");
     }
+
+    QuotaManager* quotaManager = QuotaManager::Get();
+    NS_ASSERTION(quotaManager, "Shouldn't be null!");
+
+    quotaManager->RemoveQuotaForPattern(mOriginOrPattern);
+
+    aManager->UninitializeOriginsByPattern(mOriginOrPattern);
   }
 }
 
 NS_IMETHODIMP
 IndexedDatabaseManager::OriginClearRunnable::Run()
 {
   IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
   NS_ASSERTION(mgr, "This should never fail!");
@@ -1875,29 +1873,16 @@ IndexedDatabaseManager::AsyncUsageRunnab
 void
 IndexedDatabaseManager::AsyncUsageRunnable::Cancel()
 {
   if (PR_ATOMIC_SET(&mCanceled, 1)) {
     NS_ERROR("Canceled more than once?!");
   }
 }
 
-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()
 {
   NS_ASSERTION(mCallbackState == Pending, "Huh?");
 
   nsresult rv = NS_DispatchToCurrentThread(this);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -2290,35 +2275,32 @@ IndexedDatabaseManager::AsyncDeleteFileR
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
   nsCOMPtr<nsIFile> directory = mFileManager->GetDirectory();
   NS_ENSURE_TRUE(directory, NS_ERROR_FAILURE);
 
   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);
-
-  int rc = sqlite3_quota_remove(NS_ConvertUTF16toUTF8(filePath).get());
-  if (rc != SQLITE_OK) {
-    NS_WARNING("Failed to delete stored file!");
-    return NS_ERROR_FAILURE;
+  nsresult rv;
+  int64_t fileSize;
+
+  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);
-
-  if (exists) {
-    rv = file->Remove(false);
-    NS_ENSURE_SUCCESS(rv, rv);
+  rv = file->Remove(false);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+
+  if (mFileManager->Privilege() != Chrome) {
+    QuotaManager* quotaManager = QuotaManager::Get();
+    NS_ASSERTION(quotaManager, "Shouldn't be null!");
+
+    quotaManager->DecreaseUsageForOrigin(mFileManager->Origin(), fileSize);
   }
 
   directory = mFileManager->GetJournalDirectory();
   NS_ENSURE_TRUE(directory, NS_ERROR_FAILURE);
 
   file = mFileManager->GetFileForId(directory, mFileId);
   NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
 
--- a/dom/indexedDB/IndexedDatabaseManager.h
+++ b/dom/indexedDB/IndexedDatabaseManager.h
@@ -18,17 +18,16 @@
 #include "nsIURI.h"
 
 #include "nsClassHashtable.h"
 #include "nsRefPtrHashtable.h"
 #include "nsHashKeys.h"
 
 #define INDEXEDDB_MANAGER_CONTRACTID "@mozilla.org/dom/indexeddb/manager;1"
 
-class mozIStorageQuotaCallback;
 class nsIAtom;
 class nsIFile;
 class nsITimer;
 class nsPIDOMWindow;
 class nsEventChainPostVisitor;
 
 namespace mozilla {
 namespace dom {
@@ -129,16 +128,18 @@ public:
 
   static uint32_t
   GetIndexedDBQuotaMB();
 
   nsresult EnsureOriginIsInitialized(const nsACString& aOrigin,
                                      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
   QuotaIsLifted()
   {
     IndexedDatabaseManager* mgr = Get();
     NS_ASSERTION(mgr, "Must have a manager here!");
 
@@ -167,19 +168,17 @@ public:
   }
 #endif
 
   already_AddRefed<FileManager>
   GetFileManager(const nsACString& aOrigin,
                  const nsAString& aDatabaseName);
 
   void
-  AddFileManager(const nsACString& aOrigin,
-                 const nsAString& aDatabaseName,
-                 FileManager* aFileManager);
+  AddFileManager(FileManager* aFileManager);
 
   void InvalidateFileManagersForPattern(const nsACString& aPattern);
 
   void InvalidateFileManager(const nsACString& aOrigin,
                              const nsAString& aDatabaseName);
 
   nsresult AsyncDeleteFile(FileManager* aFileManager,
                            int64_t aFileId);
@@ -497,20 +496,16 @@ private:
   nsAutoTArray<nsAutoPtr<SynchronizedOp>, 5> mSynchronizedOps;
 
   // Thread on which IO is performed.
   nsCOMPtr<nsIThread> mIOThread;
 
   // 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;
 
   // Lock protecting FileManager.mFileInfos and nsDOMFileBase.mFileInfos
   // It's s also used to atomically update FileInfo.mRefCnt, FileInfo.mDBRefCnt
   // and FileInfo.mSliceRefCnt
   mozilla::Mutex mFileMutex;
--- a/dom/indexedDB/Makefile.in
+++ b/dom/indexedDB/Makefile.in
@@ -20,17 +20,16 @@ EXPORTS_NAMESPACES = mozilla/dom/indexed
 
 CPPSRCS = \
   AsyncConnectionHelper.cpp \
   CheckPermissionsHelper.cpp \
   CheckQuotaHelper.cpp \
   DatabaseInfo.cpp \
   FileInfo.cpp \
   FileManager.cpp \
-  FileStream.cpp \
   IDBCursor.cpp \
   IDBDatabase.cpp \
   IDBEvents.cpp \
   IDBFactory.cpp \
   IDBFileHandle.cpp \
   IDBIndex.cpp \
   IDBKeyRange.cpp \
   IDBObjectStore.cpp \
@@ -88,17 +87,16 @@ XPIDLSRCS = \
   nsIIDBIndex.idl \
   nsIIDBKeyRange.idl \
   nsIIDBObjectStore.idl \
   nsIIDBRequest.idl \
   nsIIDBTransaction.idl \
   nsIIDBVersionChangeEvent.idl \
   nsIIDBOpenDBRequest.idl \
   nsIIndexedDatabaseManager.idl \
-  nsIStandardFileStream.idl \
   $(NULL)
 
 DIRS += ipc
 TEST_DIRS += test
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
--- a/dom/indexedDB/OpenDatabaseHelper.cpp
+++ b/dom/indexedDB/OpenDatabaseHelper.cpp
@@ -3,29 +3,31 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/DebugOnly.h"
 
 #include "OpenDatabaseHelper.h"
 
 #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"
 #include "IDBFactory.h"
 #include "IndexedDatabaseManager.h"
 
 using namespace mozilla;
 USING_INDEXEDDB_NAMESPACE
+USING_QUOTA_NAMESPACE
 
 namespace {
 
 // If JS_STRUCTURED_CLONE_VERSION changes then we need to update our major
 // schema version.
 MOZ_STATIC_ASSERT(JS_STRUCTURED_CLONE_VERSION == 1,
                   "Need to update the major schema version.");
 
@@ -1627,25 +1629,25 @@ OpenDatabaseHelper::DoDatabaseWork()
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = dbFile->Append(filename + NS_LITERAL_STRING(".sqlite"));
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   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) {
     rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = IDBFactory::LoadDatabaseInformation(connection, mDatabaseId,
@@ -1686,77 +1688,79 @@ OpenDatabaseHelper::DoDatabaseWork()
   }
 
   if (mCurrentVersion != mRequestedVersion) {
     mState = eSetVersionPending;
   }
 
   nsRefPtr<FileManager> fileManager = mgr->GetFileManager(mASCIIOrigin, mName);
   if (!fileManager) {
-    fileManager = new FileManager(mASCIIOrigin, mName);
-
-    rv = fileManager->Init(fileManagerDirectory, connection);
+    fileManager = new FileManager(mASCIIOrigin, mPrivilege, mName);
+
+    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();
 
   return NS_OK;
 }
 
 // static
 nsresult
 OpenDatabaseHelper::CreateDatabaseConnection(
+                                        nsIFile* aDBFile,
+                                        nsIFile* aFMDirectory,
                                         const nsAString& aName,
-                                        nsIFile* aDBFile,
-                                        nsIFile* aFileManagerDirectory,
+                                        const nsACString& aOrigin,
                                         mozIStorageConnection** aConnection)
 {
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
-  NS_NAMED_LITERAL_CSTRING(quotaVFSName, "quota");
-
-  nsCOMPtr<mozIStorageServiceQuotaManagement> ss =
+  nsCOMPtr<nsIFileURL> dbFileUrl =
+    IDBFactory::GetDatabaseFileURL(aDBFile, aOrigin);
+  NS_ENSURE_TRUE(dbFileUrl, NS_ERROR_FAILURE);
+
+  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
     // initialization too.
     if (aName.IsVoid()) {
       return rv;
     }
 
     // Nuke the database file.  The web services can recreate their data.
     rv = aDBFile->Remove(false);
     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);
 
   rv = connection->EnableModule(NS_LITERAL_CSTRING("filesystem"));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Check to make sure that the database schema is correct.
   int32_t schemaVersion;
@@ -2342,16 +2346,18 @@ SetVersionHelper::NotifyTransactionPostC
   return rv;
 }
 
 nsresult
 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!");
 
   nsCOMPtr<nsIFile> directory;
   nsresult rv = mgr->GetDirectoryForOrigin(mASCIIOrigin,
                                            getter_AddRefs(directory));
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
@@ -2367,69 +2373,67 @@ DeleteDatabaseHelper::DoDatabaseWork(moz
 
   rv = dbFile->Append(filename + NS_LITERAL_STRING(".sqlite"));
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   bool exists = false;
   rv = dbFile->Exists(&exists);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  int rc;
-
   if (exists) {
-    nsString dbFilePath;
-    rv = dbFile->GetPath(dbFilePath);
+    int64_t fileSize;
+
+    if (privilege != Chrome) {
+      rv = dbFile->GetFileSize(&fileSize);
+      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    }
+
+    rv = dbFile->Remove(false);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-    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;
-    }
-
-    // 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);
-    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);
-
-  rv = fileManagerDirectory->Append(filename);
+  nsCOMPtr<nsIFile> fmDirectory;
+  rv = directory->Clone(getter_AddRefs(fmDirectory));
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  rv = fileManagerDirectory->Exists(&exists);
+  rv = fmDirectory->Append(filename);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  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);
+    uint64_t usage = 0;
+
+    if (privilege != Chrome) {
+      rv = FileManager::GetUsage(fmDirectory, &usage);
+      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    }
+
+    rv = fmDirectory->Remove(true);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-    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) {
+      QuotaManager* quotaManager = QuotaManager::Get();
+      NS_ASSERTION(quotaManager, "Shouldn't be null!");
+
+      quotaManager->DecreaseUsageForOrigin(mASCIIOrigin, usage);
     }
-
-    rv = fileManagerDirectory->Remove(true);
-    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 nsresult
 DeleteDatabaseHelper::GetSuccessResult(JSContext* aCx, jsval* aVal)
 {
--- a/dom/indexedDB/OpenDatabaseHelper.h
+++ b/dom/indexedDB/OpenDatabaseHelper.h
@@ -72,20 +72,26 @@ public:
   }
 
   IDBDatabase* Database() const
   {
     NS_ASSERTION(mDatabase, "Calling at the wrong time!");
     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:
   // Methods only called on the main thread
   nsresult EnsureSuccessResult();
   nsresult StartSetVersion();
   nsresult StartDelete();
   virtual nsresult GetSuccessResult(JSContext* aCx,
deleted file mode 100644
--- a/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();
-};
--- a/dom/indexedDB/test/Makefile.in
+++ b/dom/indexedDB/test/Makefile.in
@@ -49,21 +49,23 @@ MOCHITEST_FILES = \
   test_event_source.html \
   test_exceptions_in_events.html \
   test_file_array.html \
   test_file_cross_database_copying.html \
   test_file_delete.html \
   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 \
   test_get_filehandle.html \
   test_global_data.html \
   test_index_empty_keyPath.html \
   test_index_getAll.html \
   test_index_getAllObjects.html \
--- a/dom/indexedDB/test/file.js
+++ b/dom/indexedDB/test/file.js
@@ -1,13 +1,15 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
+const DEFAULT_QUOTA = 50 * 1024 * 1024;
+
 var bufferCache = [];
 var utils = SpecialPowers.getDOMWindowUtils(window);
 
 if (!SpecialPowers.isMainProcess()) {
   window.runTest = function() {
     todo(false, "Test disabled in child processes, for now");
     finishTest();
   }
@@ -179,35 +181,16 @@ function getUsage(usageHandler)
     onUsageResult: function(uri, usage, fileUsage) {
       usageHandler(usage, fileUsage);
     }
   };
 
   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);
 }
 
 function getFileId(file)
 {
   return utils.getFileId(file);
--- a/dom/indexedDB/test/test_file_quota.html
+++ b/dom/indexedDB/test/test_file_quota.html
@@ -8,50 +8,44 @@
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   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;
     request.onupgradeneeded = grabEventAndContinueHandler;
     request.onsuccess = grabEventAndContinueHandler;
     let event = yield;
 
     is(event.type, "upgradeneeded", "Got correct event type");
 
     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;
 
     trans.oncomplete = grabEventAndContinueHandler;
     event = yield;
 
     is(event.type, "complete", "Got correct event type");
 
--- a/dom/indexedDB/test/test_filehandle_quota.html
+++ b/dom/indexedDB/test/test_filehandle_quota.html
@@ -8,17 +8,16 @@
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
   function testSteps()
   {
     const READ_WRITE = IDBTransaction.READ_WRITE;
-    const DEFAULT_QUOTA_MB = 50;
 
     const name = window.location.pathname;
 
     let request = indexedDB.open(name, 1);
     request.onerror = errorHandler;
     request.onupgradeneeded = grabEventAndContinueHandler;
     request.onsuccess = grabEventAndContinueHandler;
     let event = yield;
@@ -34,20 +33,20 @@
     request.onsuccess = grabEventAndContinueHandler;
     event = yield;
 
     let fileHandle = event.target.result;
     fileHandle.onerror = errorHandler;
 
     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;
 
     lockedFile.oncomplete = grabEventAndContinueHandler;
     event = yield;
 
     is(event.type, "complete", "Got correct event type");
 
new file mode 100644
--- /dev/null
+++ b/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();
+}
new file mode 100644
--- /dev/null
+++ b/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__ */
new file mode 100644
--- /dev/null
+++ b/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
new file mode 100644
--- /dev/null
+++ b/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__
new file mode 100644
--- /dev/null
+++ b/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);
+}
new file mode 100644
--- /dev/null
+++ b/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__ */
--- a/layout/build/Makefile.in
+++ b/layout/build/Makefile.in
@@ -64,16 +64,17 @@ SHARED_LIBRARY_LIBS = \
 	$(DEPTH)/dom/base/$(LIB_PREFIX)jsdombase_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/battery/$(LIB_PREFIX)dom_battery_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/contacts/$(LIB_PREFIX)jsdomcontacts_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/alarm/$(LIB_PREFIX)domalarm_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/devicestorage/$(LIB_PREFIX)domdevicestorage_s.$(LIB_SUFFIX) \
 	$(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) \
 	$(DEPTH)/dom/media/$(LIB_PREFIX)dom_media_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/sms/src/$(LIB_PREFIX)dom_sms_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/src/events/$(LIB_PREFIX)jsdomevents_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/src/json/$(LIB_PREFIX)json_s.$(LIB_SUFFIX) \
 	$(DEPTH)/dom/src/jsurl/$(LIB_PREFIX)jsurl_s.$(LIB_SUFFIX) \
--- a/netwerk/base/src/Makefile.in
+++ b/netwerk/base/src/Makefile.in
@@ -14,16 +14,17 @@ include $(DEPTH)/config/autoconf.mk
 
 MODULE		= necko
 LIBRARY_NAME	= neckobase_s
 LIBXUL_LIBRARY  = 1
 
 EXPORTS = \
 		nsMIMEInputStream.h \
 		nsURLHelper.h \
+		nsFileStreams.h \
 		$(NULL)
 
 EXPORTS_NAMESPACES = mozilla/net
 
 EXPORTS_mozilla/net = \
 		Dashboard.h \
 		DashboardTypes.h \
 		$(NULL)
--- a/netwerk/base/src/nsFileStreams.cpp
+++ b/netwerk/base/src/nsFileStreams.cpp
@@ -46,17 +46,19 @@ nsFileStreamBase::nsFileStreamBase()
 {
 }
 
 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)
 {
     nsresult rv = DoPendingOpen();
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (mFD == nullptr)
@@ -119,16 +121,62 @@ nsFileStreamBase::SetEOF()
     }
 #else
     // XXX not implemented
 #endif
 
     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()
 {
     CleanUpOpen();
 
     nsresult rv = NS_OK;
     if (mFD) {
         if (PR_Close(mFD) == PR_FAILURE)
@@ -929,23 +977,22 @@ nsSafeFileOutputStream::Write(const char
             NS_WARNING("writing to output stream failed! data may be lost");
     } 
     return rv;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // 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)
 {
     NS_ENSURE_TRUE(mFD == nullptr, NS_ERROR_ALREADY_INITIALIZED);
     NS_ENSURE_TRUE(!mDeferredOpen, NS_ERROR_ALREADY_INITIALIZED);
 
     mBehaviorFlags = behaviorFlags;
@@ -954,55 +1001,9 @@ nsFileStream::Init(nsIFile* file, int32_
         ioFlags = PR_RDWR;
     if (perm <= 0)
         perm = 0;
 
     return MaybeOpen(file, ioFlags, 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;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
--- a/netwerk/base/src/nsFileStreams.h
+++ b/netwerk/base/src/nsFileStreams.h
@@ -19,21 +19,23 @@
 #include "prlog.h"
 #include "prio.h"
 #include "nsIIPCSerializableInputStream.h"
 #include "nsReadLine.h"
 
 
 ////////////////////////////////////////////////////////////////////////////////
 
-class nsFileStreamBase : public nsISeekableStream
+class nsFileStreamBase : public nsISeekableStream,
+                         public nsIFileMetadata
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSISEEKABLESTREAM
+    NS_DECL_NSIFILEMETADATA
 
     nsFileStreamBase();
     virtual ~nsFileStreamBase();
 
 protected:
     nsresult Close();
     nsresult Available(uint64_t* _retval);
     nsresult Read(char* aBuf, uint32_t aCount, uint32_t* _retval);
@@ -119,18 +121,18 @@ public:
                             uint32_t aCount, uint32_t* _retval)
     {
         return nsFileStreamBase::ReadSegments(aWriter, aClosure, aCount,
                                               _retval);
     }
     NS_IMETHOD IsNonBlocking(bool* _retval)
     {
         return nsFileStreamBase::IsNonBlocking(_retval);
-    } 
-    
+    }
+
     // Overrided from nsFileStreamBase
     NS_IMETHOD Seek(int32_t aWhence, int64_t aOffset);
 
     nsFileInputStream()
       : mLineBuffer(nullptr), mIOFlags(0), mPerm(0), mCachedPosition(0)
     {}
 
     virtual ~nsFileInputStream()
@@ -255,23 +257,21 @@ protected:
     nsresult mWriteResult; // Internally set in Write()
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 
 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
     // Close() and IsNonBlocking() 
     NS_IMETHOD Flush()
     {
         return nsFileStreamBase::Flush();
     }
--- a/storage/public/Makefile.in
+++ b/storage/public/Makefile.in
@@ -31,17 +31,16 @@ XPIDLSRCS = \
   mozIStorageStatementRow.idl \
   mozIStorageStatementCallback.idl \
   mozIStoragePendingStatement.idl \
   mozIStorageBindingParamsArray.idl \
   mozIStorageBindingParams.idl \
   mozIStorageCompletionCallback.idl \
   mozIStorageBaseStatement.idl \
   mozIStorageAsyncStatement.idl \
-  mozIStorageServiceQuotaManagement.idl \
   mozIStorageVacuumParticipant.idl \
 	$(NULL)
 # SEE ABOVE NOTE!
 
 EXPORTS_NAMESPACES = mozilla mozilla/storage
 
 EXPORTS = \
 	mozStorageHelper.h \
--- a/storage/public/mozIStorageService.idl
+++ b/storage/public/mozIStorageService.idl
@@ -2,25 +2,26 @@
 /* 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;
+interface nsIFileURL;
 
 /**
  * The mozIStorageService interface is intended to be implemented by
  * a service that can create storage connections (mozIStorageConnection)
  * to either a well-known profile database or to a specific database file.
  *
  * 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.
    *
    * @param aStorageKey a string key identifying the type of storage
    * requested.  Valid values include: "profile", "memory".
    *
    * @see openDatabase for restrictions on how database connections may be
@@ -101,16 +102,26 @@ interface mozIStorageService : nsISuppor
    *
    * @throws NS_ERROR_OUT_OF_MEMORY
    *         If allocating a new storage object fails.
    * @throws NS_ERROR_FILE_CORRUPTED
    *         If the database file is corrupted.
    */
   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
    */
 
   /**
    * Copies the specified database file to the specified parent directory with
    * the specified file name.  If the parent directory is not specified, it
    * places the backup in the same directory as the current file.  This function
deleted file mode 100644
--- a/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);
-};
--- a/storage/public/storage.h
+++ b/storage/public/storage.h
@@ -19,17 +19,16 @@
 #include "mozIStorageProgressHandler.h"
 #include "mozIStorageResultSet.h"
 #include "mozIStorageRow.h"
 #include "mozIStorageService.h"
 #include "mozIStorageStatement.h"
 #include "mozIStorageStatementCallback.h"
 #include "mozIStorageBindingParamsArray.h"
 #include "mozIStorageBindingParams.h"
-#include "mozIStorageServiceQuotaManagement.h"
 #include "mozIStorageVacuumParticipant.h"
 #include "mozIStorageCompletionCallback.h"
 #include "mozIStorageAsyncStatement.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Native Language Helpers
 
 #include "mozStorageHelper.h"
--- a/storage/src/TelemetryVFS.cpp
+++ b/storage/src/TelemetryVFS.cpp
@@ -5,30 +5,32 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <string.h>
 #include "mozilla/Telemetry.h"
 #include "mozilla/Preferences.h"
 #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
  * that the profile exists on an NFS share whose implementation
  * is incompatible with SQLite's default locking implementation.
  * Bug 433129 attempted to automatically identify such file-systems, 
  * but a reliable way was not found and it was determined that the fallback 
  * locking is slower than POSIX locking, so we do not want to do it by default.
 */
 #define PREF_NFS_FILESYSTEM   "storage.nfs_filesystem"
 
 namespace {
 
 using namespace mozilla;
+using namespace mozilla::dom::quota;
 
 struct Histograms {
   const char *name;
   const Telemetry::ID readB;
   const Telemetry::ID writeB;
   const Telemetry::ID readMS;
   const Telemetry::ID writeMS;
   const Telemetry::ID syncMS;
@@ -77,33 +79,42 @@ public:
   }
 
 private:
   const TimeStamp start;
   const Telemetry::ID id;
 };
 
 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];
 };
 
 /*
 ** Close a telemetry_file.
 */
 int
 xClose(sqlite3_file *pFile)
 {
   telemetry_file *p = (telemetry_file *)pFile;
   int rc;
   rc = p->pReal->pMethods->xClose(p->pReal);
   if( rc==SQLITE_OK ){
     delete p->base.pMethods;
     p->base.pMethods = NULL;
+    p->quotaObject = nullptr;
   }
   return rc;
 }
 
 /*
 ** Read data from a telemetry_file.
 */
 int
@@ -121,16 +132,19 @@ xRead(sqlite3_file *pFile, void *zBuf, i
 
 /*
 ** Write data to a telemetry_file.
 */
 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);
   Telemetry::Accumulate(p->histograms->writeB, rc == SQLITE_OK ? iAmt : 0);
   return rc;
 }
 
 /*
@@ -139,16 +153,19 @@ xWrite(sqlite3_file *pFile, const void *
 int
 xTruncate(sqlite3_file *pFile, sqlite_int64 size)
 {
   IOThreadAutoTimer ioTimer(Telemetry::MOZ_SQLITE_TRUNCATE_MS);
   telemetry_file *p = (telemetry_file *)pFile;
   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;
 }
 
 /*
 ** Sync a telemetry_file.
 */
 int
 xSync(sqlite3_file *pFile, int flags)
@@ -295,16 +312,28 @@ xOpen(sqlite3_vfs* vfs, const char *zNam
     if (!match)
       continue;
     char c = match[strlen(h->name)];
     // include -wal/-journal too
     if (!c || c == '-')
       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;
   if( p->pReal->pMethods ){
     sqlite3_io_methods *pNew = new sqlite3_io_methods;
     const sqlite3_io_methods *pSub = p->pReal->pMethods;
     memset(pNew, 0, sizeof(*pNew));
     pNew->iVersion = pSub->iVersion;
--- a/storage/src/mozStorageConnection.cpp
+++ b/storage/src/mozStorageConnection.cpp
@@ -7,16 +7,17 @@
 #include <stdio.h>
 
 #include "nsError.h"
 #include "nsIMutableArray.h"
 #include "nsAutoPtr.h"
 #include "nsIMemoryReporter.h"
 #include "nsThreadUtils.h"
 #include "nsIFile.h"
+#include "nsIFileURL.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/CondVar.h"
 #include "mozilla/Attributes.h"
 
 #include "mozIStorageAggregateFunction.h"
 #include "mozIStorageCompletionCallback.h"
 #include "mozIStorageFunction.h"
@@ -466,44 +467,93 @@ Connection::getAsyncExecutionTarget()
     naming.SetThreadPoolName(NS_LITERAL_CSTRING("mozStorage"),
                              mAsyncExecutionThread);
   }
 
   return mAsyncExecutionThread;
 }
 
 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));
 
 #ifdef PR_LOGGING
   if (!gStorageLog)
     gStorageLog = ::PR_NewLogModule("mozStorage");
 
   ::sqlite3_trace(mDBConn, tracefunc, this);
@@ -517,24 +567,24 @@ Connection::initialize(nsIFile *aDatabas
 
   // Set page_size to the preferred default value.  This is effective only if
   // the database has just been created, otherwise, if the database does not
   // use WAL journal mode, a VACUUM operation will updated its page_size.
   int64_t pageSize = DEFAULT_PAGE_SIZE;
   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);
     }
     (void)::sqlite3_finalize(stmt);
   }
 
   // Setting the cache_size forces the database open, verifying if it is valid
@@ -957,17 +1007,18 @@ Connection::Clone(bool aReadOnly,
     // Turn off SQLITE_OPEN_READWRITE, and set SQLITE_OPEN_READONLY.
     flags = (~SQLITE_OPEN_READWRITE & flags) | SQLITE_OPEN_READONLY;
     // Turn off SQLITE_OPEN_CREATE.
     flags = (~SQLITE_OPEN_CREATE & flags);
   }
   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.
   static const char * pragmas[] = {
     "cache_size",
     "temp_store",
     "foreign_keys",
     "journal_size_limit",
--- a/storage/src/mozStorageConnection.h
+++ b/storage/src/mozStorageConnection.h
@@ -20,16 +20,17 @@
 
 #include "nsIMutableArray.h"
 #include "mozilla/Attributes.h"
 
 #include "sqlite3.h"
 
 struct PRLock;
 class nsIFile;
+class nsIFileURL;
 class nsIEventTarget;
 class nsIThread;
 
 namespace mozilla {
 namespace storage {
 
 class Connection MOZ_FINAL : public mozIStorageConnection
                            , public nsIInterfaceRequestor
@@ -58,28 +59,37 @@ public:
    *        Pointer to the storage service.  Held onto for the lifetime of the
    *        connection.
    * @param aFlags
    *        The flags to pass to sqlite3_open_v2.
    */
   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; }
   operator sqlite3 *() const { return mDBConn; }
 
   /**
    * Lazily creates and returns a background execution thread.  In the future,
    * the thread may be re-claimed if left idle, so you should call this
@@ -150,16 +160,18 @@ public:
    * True if this is an async connection, it is shutting down and it is not
    * closed yet.
    */
   bool isAsyncClosing();
 
 private:
   ~Connection();
 
+  nsresult initializeInternal(nsIFile *aDatabaseFile);
+
   /**
    * Sets the database into a closed state so no further actions can be
    * performed.
    *
    * @note mDBConn is set to NULL in this method.
    */
   nsresult setClosedState();
 
@@ -201,16 +213,17 @@ private:
 
   static int sProgressHelper(void *aArg);
   // Generic progress handler
   // Dispatch call to registered progress handler,
   // if there is one. Do nothing in other cases.
   int progressHandler();
 
   sqlite3 *mDBConn;
+  nsCOMPtr<nsIFileURL> mFileURL;
   nsCOMPtr<nsIFile> mDatabaseFile;
 
   /**
    * Lazily created thread for asynchronous statement execution.  Consumers
    * should use getAsyncExecutionTarget rather than directly accessing this
    * field.
    */
   nsCOMPtr<nsIThread> mAsyncExecutionThread;
--- a/storage/src/mozStorageService.cpp
+++ b/storage/src/mozStorageService.cpp
@@ -19,82 +19,25 @@
 #include "nsILocale.h"
 #include "nsILocaleService.h"
 #include "nsIXPConnect.h"
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
 #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...
 #undef CompareString
 #endif
 
 #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
 
 #define PREF_TS_SYNCHRONOUS "toolkit.storage.synchronous"
 #define PREF_TS_SYNCHRONOUS_DEFAULT 1
 
 namespace mozilla {
 namespace storage {
@@ -340,21 +283,20 @@ private:
   nsIObserver *mObserver;
   nsIXPConnect **mXPConnectPtr;
   int32_t *mSynchronousPrefValPtr;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Service
 
-NS_IMPL_THREADSAFE_ISUPPORTS3(
+NS_IMPL_THREADSAFE_ISUPPORTS2(
   Service,
   mozIStorageService,
-  nsIObserver,
-  mozIStorageServiceQuotaManagement
+  nsIObserver
 )
 
 Service *Service::gService = nullptr;
 
 Service *
 Service::getSingleton()
 {
   if (gService) {
@@ -433,20 +375,16 @@ Service::~Service()
   (void)::NS_UnregisterMemoryMultiReporter(mStorageSQLiteMultiReporter);
 
   int rc = sqlite3_vfs_unregister(mSqliteVFS);
   if (rc != SQLITE_OK)
     NS_WARNING("Failed to unregister sqlite vfs wrapper.");
 
   // 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.");
 
   DebugOnly<bool> shutdownObserved = !sXPConnect;
   NS_ASSERTION(shutdownObserved, "Shutdown was not observed!");
 
   gService = nullptr;
@@ -631,19 +569,16 @@ Service::initialize()
   mSqliteVFS = ConstructTelemetryVFS();
   if (mSqliteVFS) {
     rc = sqlite3_vfs_register(mSqliteVFS, 1);
     if (rc != SQLITE_OK)
       return convertResultCode(rc);
   } 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.
   sSynchronousPref = PREF_TS_SYNCHRONOUS_DEFAULT;
 
   // Run the things that need to run on the main thread there.
   nsCOMPtr<nsIRunnable> event =
     new ServiceMainThreadInitializer(this, this, &sXPConnect, &sSynchronousPref);
@@ -734,77 +669,90 @@ Service::OpenSpecialDatabase(const char 
   nsresult rv;
 
   nsCOMPtr<nsIFile> storageFile;
   if (::strcmp(aStorageKey, "memory") == 0) {
     // just fall through with NULL storageFile, this will cause the storage
     // 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
 Service::OpenDatabase(nsIFile *aDatabaseFile,
                       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);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  NS_ADDREF(*_connection = msc);
+  msc.forget(_connection);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Service::OpenUnsharedDatabase(nsIFile *aDatabaseFile,
                               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_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;
 }
 
 NS_IMETHODIMP
 Service::BackupDatabaseFile(nsIFile *aDBFile,
                             const nsAString &aBackupFileName,
                             nsIFile *aBackupParentDirectory,
                             nsIFile **backup)
@@ -880,72 +828,10 @@ Service::Observe(nsISupports *, const ch
       MOZ_ASSERT(!connections[i]->ConnectionReady());
     }
 #endif
   }
 
   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
--- a/storage/src/mozStorageService.h
+++ b/storage/src/mozStorageService.h
@@ -10,30 +10,28 @@
 #include "nsCOMPtr.h"
 #include "nsICollation.h"
 #include "nsIFile.h"
 #include "nsIObserver.h"
 #include "nsTArray.h"
 #include "mozilla/Mutex.h"
 
 #include "mozIStorageService.h"
-#include "mozIStorageServiceQuotaManagement.h"
 
 class nsIMemoryReporter;
 class nsIMemoryMultiReporter;
 class nsIXPConnect;
 struct sqlite3_vfs;
 
 namespace mozilla {
 namespace storage {
 
 class Connection;
 class Service : public mozIStorageService
               , public nsIObserver
-              , public mozIStorageServiceQuotaManagement
 {
 public:
   /**
    * Initializes the service.  This must be called before any other function!
    */
   nsresult initialize();
 
   /**
@@ -53,17 +51,16 @@ public:
                            const nsAString &aStr2,
                            int32_t aComparisonStrength);
 
   static Service *getSingleton();
 
   NS_DECL_ISUPPORTS
   NS_DECL_MOZISTORAGESERVICE
   NS_DECL_NSIOBSERVER
-  NS_DECL_MOZISTORAGESERVICEQUOTAMANAGEMENT
 
   /**
    * Obtains an already AddRefed pointer to XPConnect.  This is used by
    * language helpers.
    */
   static already_AddRefed<nsIXPConnect> getXPConnect();
 
   /**
--- a/toolkit/toolkit-makefiles.sh
+++ b/toolkit/toolkit-makefiles.sh
@@ -63,16 +63,17 @@ MAKEFILES_dom="
   dom/mms/interfaces/Makefile
   dom/mms/src/Makefile
   dom/network/Makefile
   dom/network/interfaces/Makefile
   dom/network/src/Makefile
   dom/plugins/base/Makefile
   dom/plugins/ipc/Makefile
   dom/power/Makefile
+  dom/quota/Makefile
   dom/settings/Makefile
   dom/sms/Makefile
   dom/sms/interfaces/Makefile
   dom/sms/src/Makefile
   dom/src/Makefile
   dom/src/events/Makefile
   dom/src/jsurl/Makefile
   dom/src/geolocation/Makefile