forked from mirrors/gecko-dev
		
	Not using a pref because Storage has connections using helper threads and the main thread, thus we prefer to avoid mutex costs for a pref we'll likely not use in Firefox. Also using a "once" pref would require some coordination because Storage may try to lazy init once prefs from different threads concurrently, causing potential deadlocks. Differential Revision: https://phabricator.services.mozilla.com/D183724
		
			
				
	
	
		
			263 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			263 lines
		
	
	
	
		
			8.9 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/. */
 | 
						|
 | 
						|
#include <string.h>
 | 
						|
#include "sqlite3.h"
 | 
						|
#include "mozilla/net/IOActivityMonitor.h"
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
// The last VFS version for which this file has been updated.
 | 
						|
constexpr int kLastKnowVfsVersion = 3;
 | 
						|
 | 
						|
// The last io_methods version for which this file has been updated.
 | 
						|
constexpr int kLastKnownIOMethodsVersion = 3;
 | 
						|
 | 
						|
using namespace mozilla;
 | 
						|
using namespace mozilla::net;
 | 
						|
 | 
						|
struct BaseFile {
 | 
						|
  // Base class.  Must be first
 | 
						|
  sqlite3_file base;
 | 
						|
  // The filename
 | 
						|
  char* location;
 | 
						|
  // This points to the underlying sqlite3_file
 | 
						|
  sqlite3_file pReal[1];
 | 
						|
};
 | 
						|
 | 
						|
int BaseClose(sqlite3_file* pFile) {
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  delete[] p->location;
 | 
						|
  return p->pReal->pMethods->xClose(p->pReal);
 | 
						|
}
 | 
						|
 | 
						|
int BaseRead(sqlite3_file* pFile, void* zBuf, int iAmt, sqlite_int64 iOfst) {
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  int rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
 | 
						|
  if (rc == SQLITE_OK && IOActivityMonitor::IsActive()) {
 | 
						|
    IOActivityMonitor::Read(nsDependentCString(p->location), iAmt);
 | 
						|
  }
 | 
						|
  return rc;
 | 
						|
}
 | 
						|
 | 
						|
int BaseWrite(sqlite3_file* pFile, const void* zBuf, int iAmt,
 | 
						|
              sqlite_int64 iOfst) {
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  int rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
 | 
						|
  if (rc == SQLITE_OK && IOActivityMonitor::IsActive()) {
 | 
						|
    IOActivityMonitor::Write(nsDependentCString(p->location), iAmt);
 | 
						|
  }
 | 
						|
  return rc;
 | 
						|
}
 | 
						|
 | 
						|
int BaseTruncate(sqlite3_file* pFile, sqlite_int64 size) {
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  return p->pReal->pMethods->xTruncate(p->pReal, size);
 | 
						|
}
 | 
						|
 | 
						|
int BaseSync(sqlite3_file* pFile, int flags) {
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  return p->pReal->pMethods->xSync(p->pReal, flags);
 | 
						|
}
 | 
						|
 | 
						|
int BaseFileSize(sqlite3_file* pFile, sqlite_int64* pSize) {
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  return p->pReal->pMethods->xFileSize(p->pReal, pSize);
 | 
						|
}
 | 
						|
 | 
						|
int BaseLock(sqlite3_file* pFile, int eLock) {
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  return p->pReal->pMethods->xLock(p->pReal, eLock);
 | 
						|
}
 | 
						|
 | 
						|
int BaseUnlock(sqlite3_file* pFile, int eLock) {
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  return p->pReal->pMethods->xUnlock(p->pReal, eLock);
 | 
						|
}
 | 
						|
 | 
						|
int BaseCheckReservedLock(sqlite3_file* pFile, int* pResOut) {
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  return p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
 | 
						|
}
 | 
						|
 | 
						|
int BaseFileControl(sqlite3_file* pFile, int op, void* pArg) {
 | 
						|
#if defined(MOZ_SQLITE_PERSIST_AUXILIARY_FILES)
 | 
						|
  // Persist auxiliary files (-shm and -wal) on disk, because creating and
 | 
						|
  // deleting them may be expensive on slow storage.
 | 
						|
  // Only do this when there is a journal size limit, so the journal is
 | 
						|
  // truncated instead of deleted on shutdown, that feels safer if the user
 | 
						|
  // moves a database file around without its auxiliary files.
 | 
						|
  MOZ_ASSERT(
 | 
						|
      ::sqlite3_compileoption_used("DEFAULT_JOURNAL_SIZE_LIMIT"),
 | 
						|
      "A journal size limit ensures the journal is truncated on shutdown");
 | 
						|
  if (op == SQLITE_FCNTL_PERSIST_WAL) {
 | 
						|
    *static_cast<int*>(pArg) = 1;
 | 
						|
    return SQLITE_OK;
 | 
						|
  }
 | 
						|
#endif
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  return p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
 | 
						|
}
 | 
						|
 | 
						|
int BaseSectorSize(sqlite3_file* pFile) {
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  return p->pReal->pMethods->xSectorSize(p->pReal);
 | 
						|
}
 | 
						|
 | 
						|
int BaseDeviceCharacteristics(sqlite3_file* pFile) {
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  return p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
 | 
						|
}
 | 
						|
 | 
						|
int BaseShmMap(sqlite3_file* pFile, int iPg, int pgsz, int bExtend,
 | 
						|
               void volatile** pp) {
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  return p->pReal->pMethods->xShmMap(p->pReal, iPg, pgsz, bExtend, pp);
 | 
						|
}
 | 
						|
 | 
						|
int BaseShmLock(sqlite3_file* pFile, int offset, int n, int flags) {
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  return p->pReal->pMethods->xShmLock(p->pReal, offset, n, flags);
 | 
						|
}
 | 
						|
 | 
						|
void BaseShmBarrier(sqlite3_file* pFile) {
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  return p->pReal->pMethods->xShmBarrier(p->pReal);
 | 
						|
}
 | 
						|
 | 
						|
int BaseShmUnmap(sqlite3_file* pFile, int deleteFlag) {
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  return p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag);
 | 
						|
}
 | 
						|
 | 
						|
int BaseFetch(sqlite3_file* pFile, sqlite3_int64 iOfst, int iAmt, void** pp) {
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  return p->pReal->pMethods->xFetch(p->pReal, iOfst, iAmt, pp);
 | 
						|
}
 | 
						|
 | 
						|
int BaseUnfetch(sqlite3_file* pFile, sqlite3_int64 iOfst, void* pPage) {
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  return p->pReal->pMethods->xUnfetch(p->pReal, iOfst, pPage);
 | 
						|
}
 | 
						|
 | 
						|
int BaseOpen(sqlite3_vfs* vfs, const char* zName, sqlite3_file* pFile,
 | 
						|
             int flags, int* pOutFlags) {
 | 
						|
  BaseFile* p = (BaseFile*)pFile;
 | 
						|
  if (zName) {
 | 
						|
    p->location = new char[7 + strlen(zName) + 1];
 | 
						|
    strcpy(p->location, "file://");
 | 
						|
    strcpy(p->location + 7, zName);
 | 
						|
  } else {
 | 
						|
    p->location = new char[8];
 | 
						|
    strcpy(p->location, "file://");
 | 
						|
  }
 | 
						|
 | 
						|
  sqlite3_vfs* origVfs = (sqlite3_vfs*)(vfs->pAppData);
 | 
						|
  int rc = origVfs->xOpen(origVfs, zName, p->pReal, flags, pOutFlags);
 | 
						|
  if (rc) {
 | 
						|
    return rc;
 | 
						|
  }
 | 
						|
  if (p->pReal->pMethods) {
 | 
						|
    // If the io_methods version is higher than the last known one, you should
 | 
						|
    // update this VFS adding appropriate IO methods for any methods added in
 | 
						|
    // the version change.
 | 
						|
    MOZ_ASSERT(p->pReal->pMethods->iVersion == kLastKnownIOMethodsVersion);
 | 
						|
    static const sqlite3_io_methods IOmethods = {
 | 
						|
        kLastKnownIOMethodsVersion, /* iVersion */
 | 
						|
        BaseClose,                  /* xClose */
 | 
						|
        BaseRead,                   /* xRead */
 | 
						|
        BaseWrite,                  /* xWrite */
 | 
						|
        BaseTruncate,               /* xTruncate */
 | 
						|
        BaseSync,                   /* xSync */
 | 
						|
        BaseFileSize,               /* xFileSize */
 | 
						|
        BaseLock,                   /* xLock */
 | 
						|
        BaseUnlock,                 /* xUnlock */
 | 
						|
        BaseCheckReservedLock,      /* xCheckReservedLock */
 | 
						|
        BaseFileControl,            /* xFileControl */
 | 
						|
        BaseSectorSize,             /* xSectorSize */
 | 
						|
        BaseDeviceCharacteristics,  /* xDeviceCharacteristics */
 | 
						|
        BaseShmMap,                 /* xShmMap */
 | 
						|
        BaseShmLock,                /* xShmLock */
 | 
						|
        BaseShmBarrier,             /* xShmBarrier */
 | 
						|
        BaseShmUnmap,               /* xShmUnmap */
 | 
						|
        BaseFetch,                  /* xFetch */
 | 
						|
        BaseUnfetch                 /* xUnfetch */
 | 
						|
    };
 | 
						|
    pFile->pMethods = &IOmethods;
 | 
						|
  }
 | 
						|
 | 
						|
  return SQLITE_OK;
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace
 | 
						|
 | 
						|
namespace mozilla::storage {
 | 
						|
 | 
						|
const char* GetBaseVFSName(bool exclusive) {
 | 
						|
  return exclusive ? "base-vfs-excl" : "base-vfs";
 | 
						|
}
 | 
						|
 | 
						|
UniquePtr<sqlite3_vfs> ConstructBaseVFS(bool exclusive) {
 | 
						|
#if defined(XP_WIN)
 | 
						|
#  define EXPECTED_VFS "win32"
 | 
						|
#  define EXPECTED_VFS_EXCL "win32"
 | 
						|
#else
 | 
						|
#  define EXPECTED_VFS "unix"
 | 
						|
#  define EXPECTED_VFS_EXCL "unix-excl"
 | 
						|
#endif
 | 
						|
 | 
						|
  if (sqlite3_vfs_find(GetBaseVFSName(exclusive))) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  bool found;
 | 
						|
  sqlite3_vfs* origVfs;
 | 
						|
  if (!exclusive) {
 | 
						|
    // Use the non-exclusive VFS.
 | 
						|
    origVfs = sqlite3_vfs_find(nullptr);
 | 
						|
    found = origVfs && origVfs->zName && !strcmp(origVfs->zName, EXPECTED_VFS);
 | 
						|
  } else {
 | 
						|
    origVfs = sqlite3_vfs_find(EXPECTED_VFS_EXCL);
 | 
						|
    found = (origVfs != nullptr);
 | 
						|
  }
 | 
						|
  if (!found) {
 | 
						|
    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(origVfs->iVersion == kLastKnowVfsVersion);
 | 
						|
 | 
						|
  sqlite3_vfs vfs = {
 | 
						|
      kLastKnowVfsVersion,                                    /* iVersion  */
 | 
						|
      origVfs->szOsFile + static_cast<int>(sizeof(BaseFile)), /* szOsFile */
 | 
						|
      origVfs->mxPathname,                                    /* mxPathname */
 | 
						|
      nullptr,                                                /* pNext */
 | 
						|
      GetBaseVFSName(exclusive),                              /* zName */
 | 
						|
      origVfs,                                                /* pAppData */
 | 
						|
      BaseOpen,                                               /* xOpen */
 | 
						|
      origVfs->xDelete,                                       /* xDelete */
 | 
						|
      origVfs->xAccess,                                       /* xAccess */
 | 
						|
      origVfs->xFullPathname,     /* xFullPathname */
 | 
						|
      origVfs->xDlOpen,           /* xDlOpen */
 | 
						|
      origVfs->xDlError,          /* xDlError */
 | 
						|
      origVfs->xDlSym,            /* xDlSym */
 | 
						|
      origVfs->xDlClose,          /* xDlClose */
 | 
						|
      origVfs->xRandomness,       /* xRandomness */
 | 
						|
      origVfs->xSleep,            /* xSleep */
 | 
						|
      origVfs->xCurrentTime,      /* xCurrentTime */
 | 
						|
      origVfs->xGetLastError,     /* xGetLastError */
 | 
						|
      origVfs->xCurrentTimeInt64, /* xCurrentTimeInt64 */
 | 
						|
      origVfs->xSetSystemCall,    /* xSetSystemCall */
 | 
						|
      origVfs->xGetSystemCall,    /* xGetSystemCall */
 | 
						|
      origVfs->xNextSystemCall    /* xNextSystemCall */
 | 
						|
  };
 | 
						|
 | 
						|
  return MakeUnique<sqlite3_vfs>(vfs);
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace mozilla::storage
 |