]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Update the quota shim so that when the same file is opened multiple times,
authordrh <drh@noemail.net>
Wed, 1 Sep 2010 12:50:54 +0000 (12:50 +0000)
committerdrh <drh@noemail.net>
Wed, 1 Sep 2010 12:50:54 +0000 (12:50 +0000)
its size only counts against the quota once.

FossilOrigin-Name: f5d263803084107389c5541face8d536b62fffe3

manifest
manifest.uuid
src/test_quota.c

index d621221d4d21b77b762ebd92218128a57491fed8..d628d785ce5b46a31b232548a6683d7b2cfc6767 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,8 @@
-C Add\sfile\stest_quota.c,\sdemonstrating\show\sfile-system\squotas\smay\sbe\simplemented\sas\sa\sVFS\swrapper.
-D 2010-09-01T11:40:05
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+C Update\sthe\squota\sshim\sso\sthat\swhen\sthe\ssame\sfile\sis\sopened\smultiple\stimes,\nits\ssize\sonly\scounts\sagainst\sthe\squota\sonce.
+D 2010-09-01T12:50:54
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in c599a15d268b1db2aeadea19df2adc3bf2eb6bee
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -208,7 +211,7 @@ F src/test_mutex.c ce06b59aca168cd8c520b77159a24352a7469bd3
 F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec
 F src/test_osinst.c f408c6a181f2fb04c56273afd5c3e1e82f60392c
 F src/test_pcache.c 7bf828972ac0d2403f5cfa4cd14da41f8ebe73d8
-F src/test_quota.c 43b7e1b2bec8fa259bc3717f67b9f5c8026724ed
+F src/test_quota.c 3bd9629e4b88d1aa7086a987a7eaee35d8683280
 F src/test_rtree.c e957a603a98871dcf005c1e96ae791cfe74eb7f6
 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
 F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
@@ -853,10 +856,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P afdc82a99eba260aed8ae2cca4bcec629f384098
-R f576cc3079f8c23a4490d6ed337ce008
-T *branch * experimental
-T *sym-experimental *
-T -sym-trunk *
-U dan
-Z da8e3747f889e65babc56beff4831221
+P 383eb87bbf560b20682dd5be0e18ddadf762f415
+R b5a4d36b9d6562d3c3442739bfabc1f0
+U drh
+Z 71992168532d47edde2bb9ee2fe75389
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.6 (GNU/Linux)
+
+iD8DBQFMfkwxoxKgR168RlERAgANAJ9B4KtMV72Ji0JYDm0FJNxZrpK+kwCfT8lT
+0hQEz4MNPkLhC93D3DNoV70=
+=rL9o
+-----END PGP SIGNATURE-----
index b7e5f5ac076cda45133ca3847b00548f7130f192..37c93b22bf40a62eb77880a3f378ff364019f054 100644 (file)
@@ -1 +1 @@
-383eb87bbf560b20682dd5be0e18ddadf762f415
\ No newline at end of file
+f5d263803084107389c5541face8d536b62fffe3
\ No newline at end of file
index 5b397431810593def2a50da5e22efdbb628fcbab..941a6376323e170db19b217bf85a9fe48912fc5b 100644 (file)
 
 /************************ Object Definitions ******************************/
 
+/* Forward declaration of all object types */
+typedef struct quotaGroup quotaGroup;
+typedef struct quotaOpen quotaOpen;
+typedef struct quotaFile quotaFile;
+
 /*
 ** This module contains a table of filename patterns that have size
 ** quotas.  The quota applies to the sum of the sizes of all open
@@ -45,7 +50,6 @@
 **
 ** Each entry in the quota table is an instance of the following object.
 */
-typedef struct quotaGroup quotaGroup;
 struct quotaGroup {
   const char *zPattern;          /* Filename pattern to be quotaed */
   sqlite3_int64 iLimit;          /* Upper bound on total file size */
@@ -57,21 +61,34 @@ struct quotaGroup {
      void *pArg                     /* Client data */
   );
   void *pArg;                    /* Third argument to the xCallback() */
-  int nRef;                      /* Number of files in the group references. */
   quotaGroup *pNext, **ppPrev;   /* Doubly linked list of all quota objects */
+  quotaFile *pFile;              /* Files within this group */
 };
 
 /*
-** An instance of the following object represents each file that
-** participates in quota tracking.  The sqlite3_file object for the
-** underlying VFS is appended to this structure.
+** 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 counting 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.
 */
-typedef struct quotaFile quotaFile;
 struct quotaFile {
-  sqlite3_file base;              /* Base class - must be first */
-  const char *zFilename;          /* Name of this file */
+  char *zFilename;                /* Name of this file */
   quotaGroup *pGroup;             /* Upper bound on file size */
   sqlite3_int64 iSize;            /* Current size of this file */
+  int nRef;                       /* Number of times this file is open */
+  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.  The sqlite3_file object
+** for the underlying VFS is appended to this structure.
+*/
+struct quotaOpen {
+  sqlite3_file base;              /* Base class - must be first */
+  quotaFile *pFile;               /* The underlying file */
   /* The underlying VFS sqlite3_file is appended to this object */
 };
 
@@ -134,7 +151,7 @@ static void quotaLeave(void){ sqlite3_mutex_leave(gQuota.pMutex); }
 ** zero, then destroy the quotaGroup.
 */
 static void quotaGroupDeref(quotaGroup *p){
-  if( p->nRef==0 && p->iLimit==0 ){
+  if( p->pFile==0 && p->iLimit==0 ){
     if( p->pNext ) p->pNext->ppPrev = p->ppPrev;
     if( p->ppPrev ) *p->ppPrev = p->pNext;
     sqlite3_free(p);
@@ -223,7 +240,7 @@ static int strglob(const char *zGlob, const char *z){
 
 /* Find a quotaGroup given the filename.
 **
-** Return a pointer to the quotaFile object. Return NULL if not found.
+** Return a pointer to the quotaOpen object. Return NULL if not found.
 */
 static quotaGroup *quotaGroupFind(const char *zFilename){
   quotaGroup *p;
@@ -231,11 +248,11 @@ static quotaGroup *quotaGroupFind(const char *zFilename){
   return p;
 }
 
-/* Translate an sqlite3_file* that is really a quotaFile* into
+/* Translate an sqlite3_file* that is really a quotaOpen* into
 ** an sqlite3_file* for the underlying original VFS.
 */
-static sqlite3_file *quotaSubFile(sqlite3_file *pFile){
-  quotaFile *p = (quotaFile*)pFile;
+static sqlite3_file *quotaSubOpen(sqlite3_file *pOpen){
+  quotaOpen *p = (quotaOpen*)pOpen;
   return (sqlite3_file*)&p[1];
 }
 
@@ -247,24 +264,25 @@ static sqlite3_file *quotaSubFile(sqlite3_file *pFile){
 ** simply links the new file into the quota group if it is a file that
 ** needs to be tracked.
 */
-static int quotaOpen(
+static int quotaxOpen(
   sqlite3_vfs *pVfs,
   const char *zName,
-  sqlite3_file *pFile,
+  sqlite3_file *pOpen,
   int flags,
   int *pOutFlags
 ){
   int rc;
-  quotaFile *pQuotaFile;
+  quotaOpen *pQuotaOpen;
+  quotaFile *pFile;
   quotaGroup *pGroup;
-  sqlite3_file *pSubFile;
+  sqlite3_file *pSubOpen;
   sqlite3_vfs *pOrigVfs = gQuota.pOrigVfs;
 
   /* 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, pFile, flags, pOutFlags);
+    return pOrigVfs->xOpen(pOrigVfs, zName, pOpen, flags, pOutFlags);
   }
 
   /* If the name of the file does not match any quota group, then
@@ -273,22 +291,39 @@ static int quotaOpen(
   quotaEnter();
   pGroup = quotaGroupFind(zName);
   if( pGroup==0 ){
-    rc = pOrigVfs->xOpen(pOrigVfs, zName, pFile, flags, pOutFlags);
+    rc = pOrigVfs->xOpen(pOrigVfs, zName, pOpen, flags, pOutFlags);
   }else{
     /* If we get to this point, it means the file needs to be quota tracked.
     */
-    pQuotaFile = (quotaFile*)pFile;
-    pSubFile = quotaSubFile(pFile);
-    rc = pOrigVfs->xOpen(pOrigVfs, zName, pSubFile, flags, pOutFlags);
+    pQuotaOpen = (quotaOpen*)pOpen;
+    pSubOpen = quotaSubOpen(pOpen);
+    rc = pOrigVfs->xOpen(pOrigVfs, zName, pSubOpen, flags, pOutFlags);
     if( rc==SQLITE_OK ){
-      pQuotaFile->iSize = 0;
-      pQuotaFile->pGroup = pGroup;
-      pGroup->nRef++;
-      pQuotaFile->zFilename = zName;
-      if( pSubFile->pMethods->iVersion==1 ){
-        pQuotaFile->base.pMethods = &gQuota.sIoMethodsV1;
+      for(pFile=pGroup->pFile; pFile && strcmp(pFile->zFilename, zName);
+          pFile=pFile->pNext){}
+      if( pFile==0 ){
+        int nName = strlen(zName);
+        pFile = sqlite3_malloc( sizeof(*pFile) + nName + 1 );
+        if( pFile==0 ){
+          quotaLeave();
+          pSubOpen->pMethods->xClose(pSubOpen);
+          return SQLITE_NOMEM;
+        }
+        memset(pFile, 0, sizeof(*pFile));
+        pFile->zFilename = (char*)&pFile[1];
+        memcpy(pFile->zFilename, zName, nName+1);
+        pFile->pNext = pGroup->pFile;
+        if( pGroup->pFile ) pGroup->pFile->ppPrev = &pFile->pNext;
+        pFile->ppPrev = &pGroup->pFile;
+        pGroup->pFile = pFile;
+        pFile->pGroup = pGroup;
+      }
+      pFile->nRef++;
+      pQuotaOpen->pFile = pFile;
+      if( pSubOpen->pMethods->iVersion==1 ){
+        pQuotaOpen->base.pMethods = &gQuota.sIoMethodsV1;
       }else{
-        pQuotaFile->base.pMethods = &gQuota.sIoMethodsV2;
+        pQuotaOpen->base.pMethods = &gQuota.sIoMethodsV2;
       }
     }
   }
@@ -299,18 +334,24 @@ static int quotaOpen(
 /************************ I/O Method Wrappers *******************************/
 
 /* xClose requests get passed through to the original VFS.  But we
-** also have to unlink the quotaFile from the quotaGroup.
+** also have to unlink the quotaOpen from the quotaGroup.
 */
-static int quotaClose(sqlite3_file *pFile){
-  quotaFile *p = (quotaFile*)pFile;
-  quotaGroup *pGroup = p->pGroup;
-  sqlite3_file *pSubFile = quotaSubFile(pFile);
+static int quotaClose(sqlite3_file *pOpen){
+  quotaOpen *p = (quotaOpen*)pOpen;
+  quotaFile *pFile = p->pFile;
+  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
   int rc;
-  rc = pSubFile->pMethods->xClose(pSubFile);
+  rc = pSubOpen->pMethods->xClose(pSubOpen);
   quotaEnter();
-  pGroup->nRef--;
-  pGroup->iSize -= p->iSize;
-  quotaGroupDeref(pGroup);
+  pFile->nRef--;
+  if( pFile->nRef==0 ){
+    quotaGroup *pGroup = pFile->pGroup;
+    pGroup->iSize -= pFile->iSize;
+    if( pFile->pNext ) pFile->pNext->ppPrev = pFile->ppPrev;
+    *pFile->ppPrev = pFile->pNext;
+    quotaGroupDeref(pGroup);
+    sqlite3_free(pFile);
+  }
   quotaLeave();
   return rc;
 }
@@ -319,13 +360,13 @@ static int quotaClose(sqlite3_file *pFile){
 ** further processing.
 */
 static int quotaRead(
-  sqlite3_file *pFile,
+  sqlite3_file *pOpen,
   void *pBuf,
   int iAmt,
   sqlite3_int64 iOfst
 ){
-  sqlite3_file *pSubFile = quotaSubFile(pFile);
-  return pSubFile->pMethods->xRead(pSubFile, pBuf, iAmt, iOfst);
+  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  return pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst);
 }
 
 /* Check xWrite requests to see if they expand the file.  If they do,
@@ -333,24 +374,25 @@ static int quotaRead(
 ** original VFS.
 */
 static int quotaWrite(
-  sqlite3_file *pFile,
+  sqlite3_file *pOpen,
   const void *pBuf,
   int iAmt,
   sqlite3_int64 iOfst
 ){
-  quotaFile *p = (quotaFile*)pFile;
-  sqlite3_file *pSubFile = quotaSubFile(pFile);
+  quotaOpen *p = (quotaOpen*)pOpen;
+  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
   sqlite3_int64 iEnd = iOfst+iAmt;
   quotaGroup *pGroup;
+  quotaFile *pFile = p->pFile;
   sqlite3_int64 szNew;
 
-  if( p->iSize<iEnd ){
-    pGroup = p->pGroup;
+  if( pFile->iSize<iEnd ){
+    pGroup = pFile->pGroup;
     quotaEnter();
-    szNew = pGroup->iSize - p->iSize + iEnd;
+    szNew = pGroup->iSize - pFile->iSize + iEnd;
     if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){
       if( pGroup->xCallback ){
-        pGroup->xCallback(p->zFilename, &pGroup->iLimit, szNew, 
+        pGroup->xCallback(pFile->zFilename, &pGroup->iLimit, szNew, 
                           pGroup->pArg);
       }
       if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){
@@ -359,24 +401,26 @@ static int quotaWrite(
       }
     }
     pGroup->iSize = szNew;
-    p->iSize = iEnd;
+    pFile->iSize = iEnd;
     quotaLeave();
   }
-  return pSubFile->pMethods->xWrite(pSubFile, pBuf, iAmt, iOfst);
+  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 *pFile, sqlite3_int64 size){
-  quotaFile *p = (quotaFile*)pFile;
-  sqlite3_file *pSubFile = quotaSubFile(pFile);
-  int rc = pSubFile->pMethods->xTruncate(pSubFile, size);
-  quotaGroup *pGroup = p->pGroup;
+static int quotaTruncate(sqlite3_file *pOpen, sqlite3_int64 size){
+  quotaOpen *p = (quotaOpen*)pOpen;
+  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  int rc = pSubOpen->pMethods->xTruncate(pSubOpen, size);
+  quotaFile *pFile = p->pFile;
+  quotaGroup *pGroup;
   if( rc==SQLITE_OK ){
     quotaEnter();
-    pGroup->iSize -= p->iSize;
-    p->iSize = size;
+    pGroup = pFile->pGroup;
+    pGroup->iSize -= pFile->iSize;
+    pFile->iSize = size;
     pGroup->iSize += size;
     quotaLeave();
   }
@@ -385,27 +429,28 @@ static int quotaTruncate(sqlite3_file *pFile, sqlite3_int64 size){
 
 /* Pass xSync requests through to the original VFS without change
 */
-static int quotaSync(sqlite3_file *pFile, int flags){
-  sqlite3_file *pSubFile = quotaSubFile(pFile);
-  return pSubFile->pMethods->xSync(pSubFile, flags);
+static int quotaSync(sqlite3_file *pOpen, int flags){
+  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  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 *pFile, sqlite3_int64 *pSize){
-  quotaFile *p = (quotaFile*)pFile;
-  sqlite3_file *pSubFile = quotaSubFile(pFile);
+static int quotaFileSize(sqlite3_file *pOpen, sqlite3_int64 *pSize){
+  quotaOpen *p = (quotaOpen*)pOpen;
+  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  quotaFile *pFile = p->pFile;
   quotaGroup *pGroup;
   sqlite3_int64 sz;
   int rc;
 
-  rc = pSubFile->pMethods->xFileSize(pSubFile, &sz);
+  rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
   if( rc==SQLITE_OK ){
-    pGroup = p->pGroup;
     quotaEnter();
-    pGroup->iSize -= p->iSize;
-    p->iSize = sz;
+    pGroup = pFile->pGroup;
+    pGroup->iSize -= pFile->iSize;
+    pFile->iSize = sz;
     pGroup->iSize += sz;
     quotaLeave();
     *pSize = sz;
@@ -415,83 +460,83 @@ static int quotaFileSize(sqlite3_file *pFile, sqlite3_int64 *pSize){
 
 /* Pass xLock requests through to the original VFS unchanged.
 */
-static int quotaLock(sqlite3_file *pFile, int lock){
-  sqlite3_file *pSubFile = quotaSubFile(pFile);
-  return pSubFile->pMethods->xLock(pSubFile, lock);
+static int quotaLock(sqlite3_file *pOpen, int lock){
+  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  return pSubOpen->pMethods->xLock(pSubOpen, lock);
 }
 
 /* Pass xUnlock requests through to the original VFS unchanged.
 */
-static int quotaUnlock(sqlite3_file *pFile, int lock){
-  sqlite3_file *pSubFile = quotaSubFile(pFile);
-  return pSubFile->pMethods->xUnlock(pSubFile, lock);
+static int quotaUnlock(sqlite3_file *pOpen, int lock){
+  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  return pSubOpen->pMethods->xUnlock(pSubOpen, lock);
 }
 
 /* Pass xCheckReservedLock requests through to the original VFS unchanged.
 */
-static int quotaCheckReservedLock(sqlite3_file *pFile, int *pResOut){
-  sqlite3_file *pSubFile = quotaSubFile(pFile);
-  return pSubFile->pMethods->xCheckReservedLock(pSubFile, pResOut);
+static int quotaCheckReservedLock(sqlite3_file *pOpen, int *pResOut){
+  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  return pSubOpen->pMethods->xCheckReservedLock(pSubOpen, pResOut);
 }
 
 /* Pass xFileControl requests through to the original VFS unchanged.
 */
-static int quotaFileControl(sqlite3_file *pFile, int op, void *pArg){
-  sqlite3_file *pSubFile = quotaSubFile(pFile);
-  return pSubFile->pMethods->xFileControl(pSubFile, op, pArg);
+static int quotaOpenControl(sqlite3_file *pOpen, int op, void *pArg){
+  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  return pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg);
 }
 
 /* Pass xSectorSize requests through to the original VFS unchanged.
 */
-static int quotaSectorSize(sqlite3_file *pFile){
-  sqlite3_file *pSubFile = quotaSubFile(pFile);
-  return pSubFile->pMethods->xSectorSize(pSubFile);
+static int quotaSectorSize(sqlite3_file *pOpen){
+  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  return pSubOpen->pMethods->xSectorSize(pSubOpen);
 }
 
 /* Pass xDeviceCharacteristics requests through to the original VFS unchanged.
 */
-static int quotaDeviceCharacteristics(sqlite3_file *pFile){
-  sqlite3_file *pSubFile = quotaSubFile(pFile);
-  return pSubFile->pMethods->xDeviceCharacteristics(pSubFile);
+static int quotaDeviceCharacteristics(sqlite3_file *pOpen){
+  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  return pSubOpen->pMethods->xDeviceCharacteristics(pSubOpen);
 }
 
 /* Pass xShmMap requests through to the original VFS unchanged.
 */
 static int quotaShmMap(
-  sqlite3_file *pFile,            /* Handle open on database file */
+  sqlite3_file *pOpen,            /* 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 *pSubFile = quotaSubFile(pFile);
-  return pSubFile->pMethods->xShmMap(pSubFile, iRegion, szRegion, bExtend, pp);
+  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  return pSubOpen->pMethods->xShmMap(pSubOpen, iRegion, szRegion, bExtend, pp);
 }
 
 /* Pass xShmLock requests through to the original VFS unchanged.
 */
 static int quotaShmLock(
-  sqlite3_file *pFile,       /* Database file holding the shared memory */
+  sqlite3_file *pOpen,       /* 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 *pSubFile = quotaSubFile(pFile);
-  return pSubFile->pMethods->xShmLock(pSubFile, ofst, n, flags);
+  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  return pSubOpen->pMethods->xShmLock(pSubOpen, ofst, n, flags);
 }
 
 /* Pass xShmBarrier requests through to the original VFS unchanged.
 */
-static void quotaShmBarrier(sqlite3_file *pFile){
-  sqlite3_file *pSubFile = quotaSubFile(pFile);
-  pSubFile->pMethods->xShmBarrier(pSubFile);
+static void quotaShmBarrier(sqlite3_file *pOpen){
+  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  pSubOpen->pMethods->xShmBarrier(pSubOpen);
 }
 
 /* Pass xShmUnmap requests through to the original VFS unchanged.
 */
-static int quotaShmUnmap(sqlite3_file *pFile, int deleteFlag){
-  sqlite3_file *pSubFile = quotaSubFile(pFile);
-  return pSubFile->pMethods->xShmUnmap(pSubFile, deleteFlag);
+static int quotaShmUnmap(sqlite3_file *pOpen, int deleteFlag){
+  sqlite3_file *pSubOpen = quotaSubOpen(pOpen);
+  return pSubOpen->pMethods->xShmUnmap(pSubOpen, deleteFlag);
 }
 
 /************************** Public Interfaces *****************************/
@@ -519,8 +564,8 @@ int sqlite3_quota_initialize(const char *zOrigVfsName, int makeDefault){
   gQuota.isInitialized = 1;
   gQuota.pOrigVfs = pOrigVfs;
   gQuota.sThisVfs = *pOrigVfs;
-  gQuota.sThisVfs.xOpen = quotaOpen;
-  gQuota.sThisVfs.szOsFile += sizeof(quotaFile);
+  gQuota.sThisVfs.xOpen = quotaxOpen;
+  gQuota.sThisVfs.szOsFile += sizeof(quotaOpen);
   gQuota.sThisVfs.zName = "quota";
   gQuota.sIoMethodsV1.iVersion = 1;
   gQuota.sIoMethodsV1.xClose = quotaClose;
@@ -532,7 +577,7 @@ int sqlite3_quota_initialize(const char *zOrigVfsName, int makeDefault){
   gQuota.sIoMethodsV1.xLock = quotaLock;
   gQuota.sIoMethodsV1.xUnlock = quotaUnlock;
   gQuota.sIoMethodsV1.xCheckReservedLock = quotaCheckReservedLock;
-  gQuota.sIoMethodsV1.xFileControl = quotaFileControl;
+  gQuota.sIoMethodsV1.xFileControl = quotaOpenControl;
   gQuota.sIoMethodsV1.xSectorSize = quotaSectorSize;
   gQuota.sIoMethodsV1.xDeviceCharacteristics = quotaDeviceCharacteristics;
   gQuota.sIoMethodsV2 = gQuota.sIoMethodsV1;
@@ -558,7 +603,7 @@ int sqlite3_quota_shutdown(void){
   quotaGroup *p;
   if( gQuota.isInitialized==0 ) return SQLITE_MISUSE;
   for(p=gQuota.pGroup; p; p=p->pNext){
-    if( p->nRef ) return SQLITE_MISUSE;
+    if( p->pFile ) return SQLITE_MISUSE;
   }
   while( gQuota.pGroup ){
     quotaGroup *p = gQuota.pGroup;