forked from mirrors/gecko-dev
		
	 2418374def
			
		
	
	
		2418374def
		
	
	
	
	
		
			
			When ignoreLockingMode option is used, we default to the unix-none or win32-none VFS, and enforce the connection to be read-only, because it's trivial to corrupt data using a no-lock VFS. Unfortunately read-only mode doesn't allow to open a WAL database if the journal files are missing, unless the device is marked as "immutable". There is no SQLITE_OPEN_* flag for immutable, and adding one could easily be misinterpreted since it only makes sense for read-only. This implement a readonly-immutable-nolock VFS shim on top of unix-none or win32-none that overrides device characteristics with immutable. When ignoreLockingMode option is specified, we use this VFS. It can only be used on read-only connections, as enforced both by Storage service and a MOZ_ASSERT. Differential Revision: https://phabricator.services.mozilla.com/D162492
		
			
				
	
	
		
			130 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			130 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 | |
|  * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
 | |
|  * 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/. */
 | |
| 
 | |
| /**
 | |
|  * This VFS is built on top of the (unix|win32)-none, but it additionally
 | |
|  * sets any opened file as immutable, that allows to also open in read-only
 | |
|  * mode databases using WAL, or other journals that need auxiliary files, when
 | |
|  * such files cannot be created.
 | |
|  * This is useful when trying to read from third-party databases, avoiding any
 | |
|  * risk of creating auxiliary files (e.g. journals).
 | |
|  * It can only be used on read-only connections, because being a no-lock VFS
 | |
|  * it would be trivial to corrupt the data.
 | |
|  */
 | |
| 
 | |
| #include "nsDebug.h"
 | |
| #include "sqlite3.h"
 | |
| 
 | |
| #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
 | |
| 
 | |
| #if defined(XP_WIN)
 | |
| #  define BASE_VFS "win32-none"
 | |
| #else
 | |
| #  define BASE_VFS "unix-none"
 | |
| #endif
 | |
| 
 | |
| #define VFS_NAME "readonly-immutable-nolock"
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| static int vfsOpen(sqlite3_vfs* vfs, const char* zName, sqlite3_file* pFile,
 | |
|                    int flags, int* pOutFlags) {
 | |
|   if ((flags & SQLITE_OPEN_READONLY) == 0) {
 | |
|     // This is not done to be used in readwrite connections.
 | |
|     return SQLITE_CANTOPEN;
 | |
|   }
 | |
| 
 | |
|   sqlite3_vfs* pOrigVfs = ORIGVFS(vfs);
 | |
|   int rc = pOrigVfs->xOpen(pOrigVfs, zName, pFile, flags, pOutFlags);
 | |
|   if (rc != SQLITE_OK) {
 | |
|     return rc;
 | |
|   }
 | |
| 
 | |
|   const sqlite3_io_methods* pOrigMethods = pFile->pMethods;
 | |
| 
 | |
|   // If the IO version is higher than the last known one, you should update
 | |
|   // this IO adding appropriate methods for any methods added in the version
 | |
|   // change.
 | |
|   MOZ_ASSERT(pOrigMethods->iVersion <= 3);
 | |
| 
 | |
|   static const sqlite3_io_methods vfs_io_methods = {
 | |
|       pOrigMethods->iVersion,           /* iVersion */
 | |
|       pOrigMethods->xClose,             /* xClose */
 | |
|       pOrigMethods->xRead,              /* xRead */
 | |
|       pOrigMethods->xWrite,             /* xWrite */
 | |
|       pOrigMethods->xTruncate,          /* xTruncate */
 | |
|       pOrigMethods->xSync,              /* xSync */
 | |
|       pOrigMethods->xFileSize,          /* xFileSize */
 | |
|       pOrigMethods->xLock,              /* xLock */
 | |
|       pOrigMethods->xUnlock,            /* xUnlock */
 | |
|       pOrigMethods->xCheckReservedLock, /* xCheckReservedLock */
 | |
|       pOrigMethods->xFileControl,       /* xFileControl */
 | |
|       pOrigMethods->xSectorSize,        /* xSectorSize */
 | |
|       [](sqlite3_file*) {
 | |
|         return SQLITE_IOCAP_IMMUTABLE;
 | |
|       },                         /* xDeviceCharacteristics */
 | |
|       pOrigMethods->xShmMap,     /* xShmMap */
 | |
|       pOrigMethods->xShmLock,    /* xShmLock */
 | |
|       pOrigMethods->xShmBarrier, /* xShmBarrier */
 | |
|       pOrigMethods->xShmUnmap,   /* xShmUnmap */
 | |
|       pOrigMethods->xFetch,      /* xFetch */
 | |
|       pOrigMethods->xUnfetch     /* xUnfetch */
 | |
|   };
 | |
|   pFile->pMethods = &vfs_io_methods;
 | |
|   if (pOutFlags) {
 | |
|     *pOutFlags = flags;
 | |
|   }
 | |
| 
 | |
|   return SQLITE_OK;
 | |
| }
 | |
| 
 | |
| }  // namespace
 | |
| 
 | |
| namespace mozilla::storage {
 | |
| 
 | |
| UniquePtr<sqlite3_vfs> ConstructReadOnlyNoLockVFS() {
 | |
|   if (sqlite3_vfs_find(VFS_NAME) != nullptr) {
 | |
|     return nullptr;
 | |
|   }
 | |
|   sqlite3_vfs* pOrigVfs = sqlite3_vfs_find(BASE_VFS);
 | |
|   if (!pOrigVfs) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   // If the VFS version is higher than the last known one, you should update
 | |
|   // this VFS adding appropriate methods for any methods added in the version
 | |
|   // change.
 | |
|   MOZ_ASSERT(pOrigVfs->iVersion <= 3);
 | |
| 
 | |
|   static const sqlite3_vfs vfs = {
 | |
|       pOrigVfs->iVersion,          /* iVersion  */
 | |
|       pOrigVfs->szOsFile,          /* szOsFile */
 | |
|       pOrigVfs->mxPathname,        /* mxPathname */
 | |
|       nullptr,                     /* pNext */
 | |
|       VFS_NAME,                    /* zName */
 | |
|       pOrigVfs,                    /* pAppData */
 | |
|       vfsOpen,                     /* xOpen */
 | |
|       pOrigVfs->xDelete,           /* xDelete */
 | |
|       pOrigVfs->xAccess,           /* xAccess */
 | |
|       pOrigVfs->xFullPathname,     /* xFullPathname */
 | |
|       pOrigVfs->xDlOpen,           /* xDlOpen */
 | |
|       pOrigVfs->xDlError,          /* xDlError */
 | |
|       pOrigVfs->xDlSym,            /* xDlSym */
 | |
|       pOrigVfs->xDlClose,          /* xDlClose */
 | |
|       pOrigVfs->xRandomness,       /* xRandomness */
 | |
|       pOrigVfs->xSleep,            /* xSleep */
 | |
|       pOrigVfs->xCurrentTime,      /* xCurrentTime */
 | |
|       pOrigVfs->xGetLastError,     /* xGetLastError */
 | |
|       pOrigVfs->xCurrentTimeInt64, /* xCurrentTimeInt64 */
 | |
|       pOrigVfs->xSetSystemCall,    /* xSetSystemCall */
 | |
|       pOrigVfs->xGetSystemCall,    /* xGetSystemCall */
 | |
|       pOrigVfs->xNextSystemCall    /* xNextSystemCall */
 | |
|   };
 | |
| 
 | |
|   return MakeUnique<sqlite3_vfs>(vfs);
 | |
| }
 | |
| 
 | |
| }  // namespace mozilla::storage
 |