diff --git a/ext/ota/ota1.test b/ext/ota/ota1.test
index 265a3d2a2f..6b8ed971da 100644
--- a/ext/ota/ota1.test
+++ b/ext/ota/ota1.test
@@ -98,7 +98,7 @@ proc step_ota {target ota} {
 #
 proc step_ota_uri {target ota} {
   while 1 {
-    sqlite3ota ota file:$target?xyz=123 $ota
+    sqlite3ota ota file:$target?xyz=&abc=123 $ota
     set rc [ota step]
     ota close
     if {$rc != "SQLITE_OK"} break
diff --git a/ext/ota/sqlite3ota.c b/ext/ota/sqlite3ota.c
index cf408b8b9f..41207501cf 100644
--- a/ext/ota/sqlite3ota.c
+++ b/ext/ota/sqlite3ota.c
@@ -85,6 +85,8 @@
 
 typedef struct OtaState OtaState;
 typedef struct OtaObjIter OtaObjIter;
+typedef struct ota_vfs ota_vfs;
+typedef struct ota_file ota_file;
 
 /*
 ** A structure to store values read from the ota_state table in memory.
@@ -156,6 +158,7 @@ struct OtaObjIter {
 #define OTA_PK_WITHOUT_ROWID  4
 #define OTA_PK_VTAB           5
 
+
 /*
 ** OTA handle.
 */
@@ -170,10 +173,31 @@ struct sqlite3ota {
   int nProgress;                  /* Rows processed for all objects */
   OtaObjIter objiter;             /* Iterator for skipping through tbl/idx */
   sqlite3_ckpt *pCkpt;            /* Incr-checkpoint handle */
-  sqlite3_vfs *pVfs;              /* Special ota VFS object */
+  ota_file *pTargetFd;            /* File handle open on target db */
+  const char *zVfsName;           /* Name of automatically created ota vfs */
   unsigned int iCookie;
 };
 
+struct ota_vfs {
+  sqlite3_vfs base;             /* ota VFS shim methods */
+  sqlite3_vfs *pRealVfs;        /* Underlying VFS */
+  sqlite3_mutex *mutex;
+  const char *zOtaWal;
+};
+
+struct ota_file {
+  sqlite3_file base;              /* sqlite3_file methods */
+  sqlite3_file *pReal;            /* Underlying file handle */
+  ota_vfs *pOtaVfs;               /* Pointer to the ota_vfs object */
+  sqlite3ota *pOta;               /* Pointer to ota object (ota target only) */
+
+  int nShm;                       /* Number of entries in apShm[] array */
+  char **apShm;                   /* Array of mmap'd *-shm regions */
+  const char *zWal;               /* Wal filename for this db file */
+  char *zDel;                     /* Delete this when closing file */
+};
+
+
 static void otaCreateVfs(sqlite3ota*, const char*);
 static void otaDeleteVfs(sqlite3ota*);
 
@@ -422,6 +446,20 @@ static int otaMPrintfExec(sqlite3ota *p, const char *zFmt, ...){
   return p->rc;
 }
 
+static void *otaMalloc(sqlite3ota *p, int nByte){
+  void *pRet = 0;
+  if( p->rc==SQLITE_OK ){
+    pRet = sqlite3_malloc(nByte);
+    if( pRet==0 ){
+      p->rc = SQLITE_NOMEM;
+    }else{
+      memset(pRet, 0, nByte);
+    }
+  }
+  return pRet;
+}
+
+
 /*
 ** Allocate and zero the pIter->azTblCol[] and abTblPk[] arrays so that
 ** there is room for at least nCol elements. If an OOM occurs, store an
@@ -431,17 +469,13 @@ static void otaAllocateIterArrays(sqlite3ota *p, OtaObjIter *pIter, int nCol){
   int nByte = (2*sizeof(char*) + sizeof(int) + 2*sizeof(unsigned char)) * nCol;
   char **azNew;
 
-  assert( p->rc==SQLITE_OK );
-  azNew = (char**)sqlite3_malloc(nByte);
+  azNew = (char**)otaMalloc(p, nByte);
   if( azNew ){
-    memset(azNew, 0, nByte);
     pIter->azTblCol = azNew;
     pIter->azTblType = &azNew[nCol];
     pIter->aiSrcOrder = (int*)&pIter->azTblType[nCol];
     pIter->abTblPk = (unsigned char*)&pIter->aiSrcOrder[nCol];
     pIter->abNotNull = (unsigned char*)&pIter->abTblPk[nCol];
-  }else{
-    p->rc = SQLITE_NOMEM;
   }
 }
 
@@ -713,19 +747,6 @@ static char *otaMPrintf(sqlite3ota *p, const char *zFmt, ...){
   return zSql;
 }
 
-static void *otaMalloc(sqlite3ota *p, int nByte){
-  void *pRet = 0;
-  if( p->rc==SQLITE_OK ){
-    pRet = sqlite3_malloc(nByte);
-    if( pRet==0 ){
-      p->rc = SQLITE_NOMEM;
-    }else{
-      memset(pRet, 0, nByte);
-    }
-  }
-  return pRet;
-}
-
 /*
 ** This function constructs and returns a pointer to a nul-terminated 
 ** string containing some SQL clause or list based on one or more of the 
@@ -991,17 +1012,14 @@ static char *otaObjIterGetSetlist(
 
 static char *otaObjIterGetBindlist(sqlite3ota *p, int nBind){
   char *zRet = 0;
-  if( p->rc==SQLITE_OK ){
-    int nByte = nBind*2 + 1;
-    zRet = sqlite3_malloc(nByte);
-    if( zRet==0 ){
-      p->rc = SQLITE_NOMEM;
-    }else{
-      int i;
-      for(i=0; i<nBind; i++){
-        zRet[i*2] = '?';
-        zRet[i*2+1] = (i+1==nBind) ? '\0' : ',';
-      }
+  int nByte = nBind*2 + 1;
+
+  zRet = (char*)otaMalloc(p, nByte);
+  if( zRet ){
+    int i;
+    for(i=0; i<nBind; i++){
+      zRet[i*2] = '?';
+      zRet[i*2+1] = (i+1==nBind) ? '\0' : ',';
     }
   }
   return zRet;
@@ -1460,11 +1478,21 @@ static void otaOpenDatabase(sqlite3ota *p){
   assert( p->rc==SQLITE_OK );
   assert( p->db==0 );
 
-  p->rc = sqlite3_open_v2(p->zTarget, &p->db, flags, p->pVfs->zName);
+  p->rc = sqlite3_open_v2(p->zTarget, &p->db, flags, p->zVfsName);
   if( p->rc ){
     p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
+  }else{
+    /* Mark the database file just opened as an OTA target database. If 
+    ** this call returns SQLITE_NOTFOUND, then the OTA vfs is not in use.
+    ** This is an error.  */
+    p->rc = sqlite3_file_control(p->db, "main", SQLITE_FCNTL_OTA, (void*)p);
+    if( p->rc==SQLITE_NOTFOUND ){
+      p->rc = SQLITE_ERROR;
+      p->zErrmsg = sqlite3_mprintf("ota vfs not found");
+    }else{
+      otaMPrintfExec(p, "ATTACH %Q AS ota", p->zOta);
+    }
   }
-  otaMPrintfExec(p, "ATTACH %Q AS ota", p->zOta);
 }
 
 /*
@@ -2039,11 +2067,14 @@ sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta){
 
     if( p->rc==SQLITE_OK ){
       if( p->eStage==OTA_STAGE_OAL ){
-        const char *zScript =
-          "PRAGMA journal_mode=off;"
-          "BEGIN IMMEDIATE;"
-        ;
-        p->rc = sqlite3_exec(p->db, zScript, 0, 0, &p->zErrmsg);
+        ota_vfs *pOtaVfs = p->pTargetFd->pOtaVfs;
+
+        sqlite3_mutex_enter(pOtaVfs->mutex);
+        assert( pOtaVfs->zOtaWal==0 );
+        pOtaVfs->zOtaWal = p->pTargetFd->zWal;
+        p->rc = sqlite3_exec(p->db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
+        pOtaVfs->zOtaWal = 0;
+        sqlite3_mutex_leave(pOtaVfs->mutex);
   
         /* Point the object iterator at the first object */
         if( p->rc==SQLITE_OK ){
@@ -2183,33 +2214,11 @@ sqlite3_int64 sqlite3ota_progress(sqlite3ota *pOta){
 **      instead.
 */
 
-typedef struct ota_file ota_file;
-typedef struct ota_vfs ota_vfs;
-
-struct ota_file {
-  sqlite3_file base;              /* sqlite3_file methods */
-  sqlite3_file *pReal;            /* Underlying file handle */
-  ota_vfs *pOtaVfs;               /* Pointer to the ota_vfs object */
-
-  int nShm;                       /* Number of entries in apShm[] array */
-  char **apShm;                   /* Array of mmap'd *-shm regions */
-  char *zFilename;                /* Filename for *-oal file only */
-};
-
-struct ota_vfs {
-  sqlite3_vfs base;             /* ota VFS shim methods */
-  sqlite3_vfs *pRealVfs;        /* Underlying VFS */
-  sqlite3ota *pOta;
-  ota_file *pTargetDb;          /* Target database file descriptor */
-  const char *zTargetDb;        /* Path that pTargetDb was opened with */
-};
-
 /*
 ** Close an ota file.
 */
 static int otaVfsClose(sqlite3_file *pFile){
   ota_file *p = (ota_file*)pFile;
-  ota_vfs *pOtaVfs = p->pOtaVfs;
   int rc;
   int i;
 
@@ -2219,12 +2228,7 @@ static int otaVfsClose(sqlite3_file *pFile){
   }
   sqlite3_free(p->apShm);
   p->apShm = 0;
-  sqlite3_free(p->zFilename);
-
-  if( p==pOtaVfs->pTargetDb ){
-    pOtaVfs->pTargetDb = 0;
-    pOtaVfs->zTargetDb = 0;
-  }
+  sqlite3_free(p->zDel);
 
   rc = p->pReal->pMethods->xClose(p->pReal);
   return rc;
@@ -2252,12 +2256,11 @@ static int otaVfsRead(
   sqlite_int64 iOfst
 ){
   ota_file *p = (ota_file*)pFile;
-  ota_vfs *pOtaVfs = p->pOtaVfs;
   int rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
-  if( rc==SQLITE_OK && p==pOtaVfs->pTargetDb && iOfst==0 ){
+  if( rc==SQLITE_OK && p->pOta && iOfst==0 ){
     unsigned char *pBuf = (unsigned char*)zBuf;
     assert( iAmt>=100 );
-    pOtaVfs->pOta->iCookie = otaGetU32(&pBuf[24]);
+    p->pOta->iCookie = otaGetU32(&pBuf[24]);
   }
   return rc;
 }
@@ -2272,12 +2275,11 @@ static int otaVfsWrite(
   sqlite_int64 iOfst
 ){
   ota_file *p = (ota_file*)pFile;
-  ota_vfs *pOtaVfs = p->pOtaVfs;
   int rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
-  if( rc==SQLITE_OK && p==pOtaVfs->pTargetDb && iOfst==0 ){
+  if( rc==SQLITE_OK && p->pOta && iOfst==0 ){
     unsigned char *pBuf = (unsigned char*)zBuf;
     assert( iAmt>=100 );
-    pOtaVfs->pOta->iCookie = otaGetU32(&pBuf[24]);
+    p->pOta->iCookie = otaGetU32(&pBuf[24]);
   }
   return rc;
 }
@@ -2311,13 +2313,11 @@ static int otaVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
 */
 static int otaVfsLock(sqlite3_file *pFile, int eLock){
   ota_file *p = (ota_file*)pFile;
-  ota_vfs *pOtaVfs = p->pOtaVfs;
+  sqlite3ota *pOta = p->pOta;
   int rc = SQLITE_OK;
-  int eStage = pOtaVfs->pOta->eStage;
 
-  if( pOtaVfs->pTargetDb==p 
-   && (eStage==OTA_STAGE_OAL || eStage==OTA_STAGE_CKPT) 
-   && eLock==SQLITE_LOCK_EXCLUSIVE
+  if( pOta && eLock==SQLITE_LOCK_EXCLUSIVE
+   && (pOta->eStage==OTA_STAGE_OAL || pOta->eStage==OTA_STAGE_CKPT) 
   ){
     /* Do not allow EXCLUSIVE locks. Preventing SQLite from taking this 
     ** prevents it from checkpointing the database from sqlite3_close(). */
@@ -2350,6 +2350,12 @@ static int otaVfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
 */
 static int otaVfsFileControl(sqlite3_file *pFile, int op, void *pArg){
   ota_file *p = (ota_file *)pFile;
+  if( op==SQLITE_FCNTL_OTA ){
+    sqlite3ota *pOta = (sqlite3ota*)pArg;
+    pOta->pTargetFd = p;
+    p->pOta = pOta;
+    return SQLITE_OK;
+  }
   return p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
 }
 
@@ -2374,14 +2380,13 @@ static int otaVfsDeviceCharacteristics(sqlite3_file *pFile){
 */
 static int otaVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
   ota_file *p = (ota_file*)pFile;
-  ota_vfs *pOtaVfs = p->pOtaVfs;
   int rc = SQLITE_OK;
 
 #ifdef SQLITE_AMALGAMATION
     assert( WAL_WRITE_CKPT==1 );
 #endif
 
-  if( pOtaVfs->pTargetDb==p && pOtaVfs->pOta->eStage==OTA_STAGE_OAL ){
+  if( p->pOta && p->pOta->eStage==OTA_STAGE_OAL ){
     /* Magic number 1 is the WAL_WRITE_CKPT lock. Preventing SQLite from
     ** taking this lock also prevents any checkpoints from occurring. 
     ** todo: really, it's not clear why this might occur, as 
@@ -2389,7 +2394,7 @@ static int otaVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
     if( ofst==1 && n==1 ) rc = SQLITE_BUSY;
   }else{
     assert( p->nShm==0 );
-    return p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
+    rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
   }
 
   return rc;
@@ -2403,13 +2408,12 @@ static int otaVfsShmMap(
   void volatile **pp
 ){
   ota_file *p = (ota_file*)pFile;
-  ota_vfs *pOtaVfs = p->pOtaVfs;
   int rc = SQLITE_OK;
 
   /* If not in OTA_STAGE_OAL, allow this call to pass through. Or, if this
   ** ota is in the OTA_STAGE_OAL state, use heap memory for *-shm space 
   ** instead of a file on disk.  */
-  if( pOtaVfs->pTargetDb==p && pOtaVfs->pOta->eStage==OTA_STAGE_OAL ){
+  if( p->pOta && p->pOta->eStage==OTA_STAGE_OAL ){
     if( iRegion<=p->nShm ){
       int nByte = (iRegion+1) * sizeof(char*);
       char **apNew = (char**)sqlite3_realloc(p->apShm, nByte);
@@ -2454,10 +2458,9 @@ static void otaVfsShmBarrier(sqlite3_file *pFile){
 
 static int otaVfsShmUnmap(sqlite3_file *pFile, int delFlag){
   ota_file *p = (ota_file*)pFile;
-  ota_vfs *pOtaVfs = p->pOtaVfs;
   int rc = SQLITE_OK;
 
-  if( pOtaVfs->pTargetDb==p && pOtaVfs->pOta->eStage==OTA_STAGE_OAL ){
+  if( p->pOta && p->pOta->eStage==OTA_STAGE_OAL ){
     /* no-op */
   }else{
     rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
@@ -2465,17 +2468,6 @@ static int otaVfsShmUnmap(sqlite3_file *pFile, int delFlag){
   return rc;
 }
 
-
-static int otaVfsIswal(ota_vfs *pOtaVfs, const char *zPath){
-  int nPath = strlen(zPath);
-  int nTargetDb = strlen(pOtaVfs->zTargetDb);
-  return ( nPath==(nTargetDb+4) 
-        && 0==memcmp(zPath, pOtaVfs->zTargetDb, nTargetDb)
-        && 0==memcmp(&zPath[nTargetDb], "-wal", 4)
-  );
-}
-
-
 /*
 ** Open an ota file handle.
 */
@@ -2507,7 +2499,6 @@ static int otaVfsOpen(
   };
   ota_vfs *pOtaVfs = (ota_vfs*)pVfs;
   sqlite3_vfs *pRealVfs = pOtaVfs->pRealVfs;
-  sqlite3ota *p = pOtaVfs->pOta;
   ota_file *pFd = (ota_file *)pFile;
   int rc = SQLITE_OK;
   const char *zOpen = zName;
@@ -2515,13 +2506,38 @@ static int otaVfsOpen(
   memset(pFd, 0, sizeof(ota_file));
   pFd->pReal = (sqlite3_file*)&pFd[1];
   pFd->pOtaVfs = pOtaVfs;
-
-  if( zName && p->eStage==OTA_STAGE_OAL && otaVfsIswal(pOtaVfs, zName) ){
-    char *zCopy = otaStrndup(zName, -1, &rc);
-    if( zCopy ){
-      int nCopy = strlen(zCopy);
-      zCopy[nCopy-3] = 'o';
-      zOpen = (const char*)(pFd->zFilename = zCopy);
+  if( zName ){
+    if( flags & SQLITE_OPEN_MAIN_DB ){
+      /* A main database has just been opened. The following block sets
+      ** (pFd->zWal) to point to a buffer owned by SQLite that contains
+      ** the name of the *-wal file this db connection will use. SQLite
+      ** happens to pass a pointer to this buffer when using xAccess()
+      ** or xOpen() to operate on the *-wal file.  */
+      int n = strlen(zName);
+      const char *z = &zName[n];
+      if( flags & SQLITE_OPEN_URI ){
+        int odd = 0;
+        while( 1 ){
+          if( z[0]==0 ){
+            odd = 1 - odd;
+            if( odd && z[1]==0 ) break;
+          }
+          z++;
+        }
+        z += 2;
+      }else{
+        while( *z==0 ) z++;
+      }
+      z += (n + 8 + 1);
+      pFd->zWal = z;
+    }
+    else if( (flags & SQLITE_OPEN_WAL) && zName==pOtaVfs->zOtaWal ){
+      char *zCopy = otaStrndup(zName, -1, &rc);
+      if( zCopy ){
+        int nCopy = strlen(zCopy);
+        zCopy[nCopy-3] = 'o';
+        zOpen = (const char*)(pFd->zDel = zCopy);
+      }
     }
   }
 
@@ -2530,13 +2546,6 @@ static int otaVfsOpen(
   }
   if( pFd->pReal->pMethods ){
     pFile->pMethods = &otavfs_io_methods;
-    if( pOtaVfs->pTargetDb==0 ){
-      /* This is the target db file. */
-      assert( (flags & SQLITE_OPEN_MAIN_DB) );
-      assert( zOpen==zName );
-      pOtaVfs->pTargetDb = pFd;
-      pOtaVfs->zTargetDb = zName;
-    }
   }
 
   return rc;
@@ -2566,11 +2575,7 @@ static int otaVfsAccess(
 
   rc = pRealVfs->xAccess(pRealVfs, zPath, flags, pResOut);
 
-  if( rc==SQLITE_OK 
-   && flags==SQLITE_ACCESS_EXISTS 
-   && pOtaVfs->pOta->eStage==OTA_STAGE_OAL 
-   && otaVfsIswal(pOtaVfs, zPath) 
-  ){
+  if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS && pOtaVfs->zOtaWal==zPath ){
     if( *pResOut ){
       rc = SQLITE_CANTOPEN;
     }else{
@@ -2666,7 +2671,15 @@ static int otaVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){
   return 0;
 }
 
-static void otaCreateVfs(sqlite3ota *p, const char *zParent){
+void sqlite3ota_destroy_vfs(const char *zName){
+  sqlite3_vfs *pVfs = sqlite3_vfs_find(zName);
+  if( pVfs ){
+    sqlite3_vfs_unregister(pVfs);
+    sqlite3_free(pVfs);
+  }
+}
+
+int sqlite3ota_create_vfs(const char *zName, const char *zParent){
 
   /* Template for VFS */
   static sqlite3_vfs vfs_template = {
@@ -2696,48 +2709,64 @@ static void otaCreateVfs(sqlite3ota *p, const char *zParent){
 
   sqlite3_vfs *pParent;           /* Parent VFS */
   ota_vfs *pNew = 0;              /* Newly allocated VFS */
+  int nName;
+  int rc = SQLITE_OK;
 
-  assert( p->rc==SQLITE_OK );
+  nName = strlen(zName);
   pParent = sqlite3_vfs_find(zParent);
   if( pParent==0 ){
-    p->rc = SQLITE_ERROR;
-    p->zErrmsg = sqlite3_mprintf("no such vfs: %s", zParent);
+    rc = SQLITE_NOTFOUND;
   }else{
-    int nByte = sizeof(ota_vfs) + 64;
-    pNew = (ota_vfs*)otaMalloc(p, nByte);
+    int nByte = sizeof(ota_vfs) + nName + 1;
+    pNew = (ota_vfs*)sqlite3_malloc(nByte);
+    if( pNew==0 ){
+      rc = SQLITE_NOMEM;
+    }else{
+      memset(pNew, 0, nByte);
+    }
   }
 
-  if( pNew ){
-    int rnd;
-    char *zName;
+  if( rc==SQLITE_OK ){
+    char *zSpace;
     memcpy(&pNew->base, &vfs_template, sizeof(sqlite3_vfs));
     pNew->base.mxPathname = pParent->mxPathname;
     pNew->base.szOsFile = sizeof(ota_file) + pParent->szOsFile;
-    pNew->pOta = p;
     pNew->pRealVfs = pParent;
 
-    /* Give the new VFS a unique name */
-    sqlite3_randomness(sizeof(int), (void*)&rnd);
-    pNew->base.zName = (const char*)(zName = (char*)&pNew[1]);
-    sprintf(zName, "ota_vfs_%d", rnd);
+    pNew->base.zName = (const char*)(zSpace = (char*)&pNew[1]);
+    memcpy(zSpace, zName, nName);
 
     /* Register the new VFS (not as the default) */
-    assert( p->rc==SQLITE_OK );
-    p->rc = sqlite3_vfs_register(&pNew->base, 0);
-    if( p->rc ){
-      p->zErrmsg = sqlite3_mprintf("error in sqlite3_vfs_register()");
+    rc = sqlite3_vfs_register(&pNew->base, 0);
+    if( rc ){
       sqlite3_free(pNew);
-    }else{
-      p->pVfs = &pNew->base;
     }
   }
+
+  return rc;
+}
+
+static void otaCreateVfs(sqlite3ota *p, const char *zParent){
+  int rnd;
+  char zRnd[64];
+
+  assert( p->rc==SQLITE_OK );
+  sqlite3_randomness(sizeof(int), (void*)&rnd);
+  sprintf(zRnd, "ota_vfs_%d", rnd);
+  p->rc = sqlite3ota_create_vfs(zRnd, zParent);
+  if( p->rc==SQLITE_NOTFOUND ){
+    p->zErrmsg = sqlite3_mprintf("no such vfs: %s", zParent);
+  }else if( p->rc==SQLITE_OK ){
+    sqlite3_vfs *pVfs = sqlite3_vfs_find(zRnd);
+    assert( pVfs );
+    p->zVfsName = pVfs->zName;
+  }
 }
 
 static void otaDeleteVfs(sqlite3ota *p){
-  if( p->pVfs ){
-    sqlite3_vfs_unregister(p->pVfs);
-    sqlite3_free(p->pVfs);
-    p->pVfs = 0;
+  if( p->zVfsName ){
+    sqlite3ota_destroy_vfs(p->zVfsName);
+    p->zVfsName = 0;
   }
 }
 
diff --git a/ext/ota/sqlite3ota.h b/ext/ota/sqlite3ota.h
index e549022f9a..f6890f4508 100644
--- a/ext/ota/sqlite3ota.h
+++ b/ext/ota/sqlite3ota.h
@@ -300,5 +300,21 @@ int sqlite3ota_close(sqlite3ota *pOta, char **pzErrmsg);
 */
 sqlite3_int64 sqlite3ota_progress(sqlite3ota *pOta);
 
+/*
+** Create an OTA VFS named zName. Use existing VFS zParent to interact
+** with the file-system.
+*/
+int sqlite3ota_create_vfs(const char *zName, const char *zParent);
+
+/*
+** Deregister and destroy an OTA vfs previously created by 
+** sqlite3ota_create_vfs().
+**
+** VFS objects are not reference counted. If a VFS object is destroyed
+** before all database handles that use it have been closed, the results 
+** are undefined.
+*/
+void sqlite3ota_destroy_vfs(const char *zName);
+
 #endif /* _SQLITE3OTA_H */
 
diff --git a/manifest b/manifest
index 777601fb6b..fe890ddfd3 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\scomments\sto\sexplain\sthe\srole\sof\sthe\sota\svfs.
-D 2015-02-07T20:20:32.171
+C Add\sthe\ssqlite3ota_create_vfs()\sand\ssqlite3ota_destroy_vfs()\sfunctions.
+D 2015-02-09T20:07:35.066
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 6b9e7677829aa94b9f30949656e27312aefb9a46
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -125,7 +125,7 @@ F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
 F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
 F ext/ota/README.txt 2ce4ffbb0aaa6731b041c27a7359f9a5f1c69152
 F ext/ota/ota.c c11a85af71dccc45976622fe7a51169a481caa91
-F ext/ota/ota1.test e6b64d6ffb23dcae72386da153626b40566a69e9
+F ext/ota/ota1.test a4779d5fe9710d607ebae360eebee3d82a1c14e6
 F ext/ota/ota10.test 85e0f6e7964db5007590c1b299e75211ed4240d4
 F ext/ota/ota3.test a77efbce7723332eb688d2b28bf18204fc9614d7
 F ext/ota/ota5.test ad0799daf8923ddebffe75ae8c5504ca90b7fadb
@@ -134,8 +134,8 @@ F ext/ota/ota7.test 1fe2c5761705374530e29f70c39693076028221a
 F ext/ota/ota8.test cd70e63a0c29c45c0906692827deafa34638feda
 F ext/ota/ota9.test d3eee95dd836824d07a22e5efcdb7bf6e869358b
 F ext/ota/otafault.test 508ba87c83d632670ac0f94371a465d4bb4d49dd
-F ext/ota/sqlite3ota.c a5cea44e3d186ae53c1a0dbdc1c3ca73e9d1dc62
-F ext/ota/sqlite3ota.h b4c54c7df5d223f2ee40efa5ba363188daa3ad37
+F ext/ota/sqlite3ota.c 3d3179fb9bcb0edf88b3391f480e84b451f1275e
+F ext/ota/sqlite3ota.h 58af0ab6361c76e0eda7aede72e7de42abf83605
 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
 F ext/rtree/rtree.c 14e6239434d4e3f65d3e90320713f26aa24e167f
 F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
@@ -245,7 +245,7 @@ F src/resolve.c f6c46d3434439ab2084618d603e6d6dbeb0d6ada
 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
 F src/select.c 1f2087523007c42900ffcbdeaef06a23ad9329fc
 F src/shell.c 82c25508dac802b32198af6f5256ca1597c6a1af
-F src/sqlite.h.in 4807b024e8d257af774cde0cf178f721ff2406ec
+F src/sqlite.h.in c49acd2daa6e54110ab0cc607eb73ff32720a269
 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
 F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
 F src/sqliteInt.h 57f8f45028598cc2877fc08ac03b402242242c68
@@ -1253,7 +1253,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 8ac58e46782bd6b81c06fdf1cb5b316b8a4e1ddf
-R f5474ed197582e342ea21c91b796b802
+P 7bb633639d1e41067903a49653f09a823054e213
+R 290f53a2e90389d88a1ff448f97370f1
 U dan
-Z 4e62cdaf7cd09d75059d0dc1ee3d7cb0
+Z 09bf3544f840f7fca63db224a647bd64
diff --git a/manifest.uuid b/manifest.uuid
index 489302fa8e..ae4cdfe82d 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-7bb633639d1e41067903a49653f09a823054e213
\ No newline at end of file
+96443ecb6909141aa621a16e628455857d036482
\ No newline at end of file
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index cdf5a8c179..23681cc6f3 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -970,6 +970,7 @@ struct sqlite3_io_methods {
 #define SQLITE_FCNTL_COMMIT_PHASETWO        22
 #define SQLITE_FCNTL_WIN32_SET_HANDLE       23
 #define SQLITE_FCNTL_ZIPVFS_PAGER           24
+#define SQLITE_FCNTL_OTA                    25
 
 /*
 ** CAPI3REF: Mutex Handle