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 116310 6328b64258aeb42d066414861ccc0e389846f4ac
parent 116309 a09a149d8a44af3f18d84cdfcd2aacf7db42f7df
child 116311 249e7db380b0e4a2da0df37aa34844c364fd42ee
push id1246
push userpastithas@mozilla.com
push dateWed, 19 Dec 2012 08:05:40 +0000
treeherderfx-team@bfd85c9652fa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent, asuth, vladan
bugs787804
milestone20.0a1
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