blob: 0da6671cf4c48832dc35bcee80f802291f9a7313 [file] [log] [blame]
/*
** 2008 Jan 22
**
** 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 code that modified the OS layer in order to simulate
** different device types (by overriding the return values of the
** xDeviceCharacteristics() and xSectorSize() methods).
*/
#if SQLITE_TEST /* This file is used for testing only */
#include "sqlite3.h"
#include "sqliteInt.h"
/*
** Maximum pathname length supported by the devsym backend.
*/
#define DEVSYM_MAX_PATHNAME 512
/*
** Name used to identify this VFS.
*/
#define DEVSYM_VFS_NAME "devsym"
#define WRITECRASH_NAME "writecrash"
typedef struct devsym_file devsym_file;
struct devsym_file {
sqlite3_file base;
sqlite3_file *pReal;
};
/*
** Method declarations for devsym_file.
*/
static int devsymClose(sqlite3_file*);
static int devsymRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
static int devsymWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
static int devsymTruncate(sqlite3_file*, sqlite3_int64 size);
static int devsymSync(sqlite3_file*, int flags);
static int devsymFileSize(sqlite3_file*, sqlite3_int64 *pSize);
static int devsymLock(sqlite3_file*, int);
static int devsymUnlock(sqlite3_file*, int);
static int devsymCheckReservedLock(sqlite3_file*, int *);
static int devsymFileControl(sqlite3_file*, int op, void *pArg);
static int devsymSectorSize(sqlite3_file*);
static int devsymDeviceCharacteristics(sqlite3_file*);
static int devsymShmLock(sqlite3_file*,int,int,int);
static int devsymShmMap(sqlite3_file*,int,int,int, void volatile **);
static void devsymShmBarrier(sqlite3_file*);
static int devsymShmUnmap(sqlite3_file*,int);
/*
** Method declarations for devsym_vfs.
*/
static int devsymOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
static int devsymDelete(sqlite3_vfs*, const char *zName, int syncDir);
static int devsymAccess(sqlite3_vfs*, const char *zName, int flags, int *);
static int devsymFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
#ifndef SQLITE_OMIT_LOAD_EXTENSION
static void *devsymDlOpen(sqlite3_vfs*, const char *zFilename);
static void devsymDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
static void (*devsymDlSym(sqlite3_vfs*,void*, const char *zSymbol))(void);
static void devsymDlClose(sqlite3_vfs*, void*);
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
static int devsymRandomness(sqlite3_vfs*, int nByte, char *zOut);
static int devsymSleep(sqlite3_vfs*, int microseconds);
static int devsymCurrentTime(sqlite3_vfs*, double*);
struct DevsymGlobal {
sqlite3_vfs *pVfs;
int iDeviceChar;
int iSectorSize;
int nWriteCrash;
};
struct DevsymGlobal g = {0, 0, 512, 0};
/*
** Close an devsym-file.
*/
static int devsymClose(sqlite3_file *pFile){
devsym_file *p = (devsym_file *)pFile;
sqlite3OsClose(p->pReal);
return SQLITE_OK;
}
/*
** Read data from an devsym-file.
*/
static int devsymRead(
sqlite3_file *pFile,
void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
}
/*
** Write data to an devsym-file.
*/
static int devsymWrite(
sqlite3_file *pFile,
const void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
}
/*
** Truncate an devsym-file.
*/
static int devsymTruncate(sqlite3_file *pFile, sqlite_int64 size){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsTruncate(p->pReal, size);
}
/*
** Sync an devsym-file.
*/
static int devsymSync(sqlite3_file *pFile, int flags){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsSync(p->pReal, flags);
}
/*
** Return the current file-size of an devsym-file.
*/
static int devsymFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsFileSize(p->pReal, pSize);
}
/*
** Lock an devsym-file.
*/
static int devsymLock(sqlite3_file *pFile, int eLock){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsLock(p->pReal, eLock);
}
/*
** Unlock an devsym-file.
*/
static int devsymUnlock(sqlite3_file *pFile, int eLock){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsUnlock(p->pReal, eLock);
}
/*
** Check if another file-handle holds a RESERVED lock on an devsym-file.
*/
static int devsymCheckReservedLock(sqlite3_file *pFile, int *pResOut){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsCheckReservedLock(p->pReal, pResOut);
}
/*
** File control method. For custom operations on an devsym-file.
*/
static int devsymFileControl(sqlite3_file *pFile, int op, void *pArg){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsFileControl(p->pReal, op, pArg);
}
/*
** Return the sector-size in bytes for an devsym-file.
*/
static int devsymSectorSize(sqlite3_file *pFile){
return g.iSectorSize;
}
/*
** Return the device characteristic flags supported by an devsym-file.
*/
static int devsymDeviceCharacteristics(sqlite3_file *pFile){
return g.iDeviceChar;
}
/*
** Shared-memory methods are all pass-thrus.
*/
static int devsymShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsShmLock(p->pReal, ofst, n, flags);
}
static int devsymShmMap(
sqlite3_file *pFile,
int iRegion,
int szRegion,
int isWrite,
void volatile **pp
){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
}
static void devsymShmBarrier(sqlite3_file *pFile){
devsym_file *p = (devsym_file *)pFile;
sqlite3OsShmBarrier(p->pReal);
}
static int devsymShmUnmap(sqlite3_file *pFile, int delFlag){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsShmUnmap(p->pReal, delFlag);
}
/*
** Open an devsym file handle.
*/
static int devsymOpen(
sqlite3_vfs *pVfs,
const char *zName,
sqlite3_file *pFile,
int flags,
int *pOutFlags
){
static sqlite3_io_methods devsym_io_methods = {
2, /* iVersion */
devsymClose, /* xClose */
devsymRead, /* xRead */
devsymWrite, /* xWrite */
devsymTruncate, /* xTruncate */
devsymSync, /* xSync */
devsymFileSize, /* xFileSize */
devsymLock, /* xLock */
devsymUnlock, /* xUnlock */
devsymCheckReservedLock, /* xCheckReservedLock */
devsymFileControl, /* xFileControl */
devsymSectorSize, /* xSectorSize */
devsymDeviceCharacteristics, /* xDeviceCharacteristics */
devsymShmMap, /* xShmMap */
devsymShmLock, /* xShmLock */
devsymShmBarrier, /* xShmBarrier */
devsymShmUnmap /* xShmUnmap */
};
int rc;
devsym_file *p = (devsym_file *)pFile;
p->pReal = (sqlite3_file *)&p[1];
rc = sqlite3OsOpen(g.pVfs, zName, p->pReal, flags, pOutFlags);
if( p->pReal->pMethods ){
pFile->pMethods = &devsym_io_methods;
}
return rc;
}
/*
** Delete the file located at zPath. If the dirSync argument is true,
** ensure the file-system modifications are synced to disk before
** returning.
*/
static int devsymDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
return sqlite3OsDelete(g.pVfs, zPath, dirSync);
}
/*
** Test for access permissions. Return true if the requested permission
** is available, or false otherwise.
*/
static int devsymAccess(
sqlite3_vfs *pVfs,
const char *zPath,
int flags,
int *pResOut
){
return sqlite3OsAccess(g.pVfs, zPath, flags, pResOut);
}
/*
** Populate buffer zOut with the full canonical pathname corresponding
** to the pathname in zPath. zOut is guaranteed to point to a buffer
** of at least (DEVSYM_MAX_PATHNAME+1) bytes.
*/
static int devsymFullPathname(
sqlite3_vfs *pVfs,
const char *zPath,
int nOut,
char *zOut
){
return sqlite3OsFullPathname(g.pVfs, zPath, nOut, zOut);
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
** Open the dynamic library located at zPath and return a handle.
*/
static void *devsymDlOpen(sqlite3_vfs *pVfs, const char *zPath){
return sqlite3OsDlOpen(g.pVfs, zPath);
}
/*
** Populate the buffer zErrMsg (size nByte bytes) with a human readable
** utf-8 string describing the most recent error encountered associated
** with dynamic libraries.
*/
static void devsymDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
sqlite3OsDlError(g.pVfs, nByte, zErrMsg);
}
/*
** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
*/
static void (*devsymDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
return sqlite3OsDlSym(g.pVfs, p, zSym);
}
/*
** Close the dynamic library handle pHandle.
*/
static void devsymDlClose(sqlite3_vfs *pVfs, void *pHandle){
sqlite3OsDlClose(g.pVfs, pHandle);
}
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
/*
** Populate the buffer pointed to by zBufOut with nByte bytes of
** random data.
*/
static int devsymRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
return sqlite3OsRandomness(g.pVfs, nByte, zBufOut);
}
/*
** Sleep for nMicro microseconds. Return the number of microseconds
** actually slept.
*/
static int devsymSleep(sqlite3_vfs *pVfs, int nMicro){
return sqlite3OsSleep(g.pVfs, nMicro);
}
/*
** Return the current time as a Julian Day number in *pTimeOut.
*/
static int devsymCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
return g.pVfs->xCurrentTime(g.pVfs, pTimeOut);
}
/*
** Return the sector-size in bytes for an writecrash-file.
*/
static int writecrashSectorSize(sqlite3_file *pFile){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsSectorSize(p->pReal);
}
/*
** Return the device characteristic flags supported by an writecrash-file.
*/
static int writecrashDeviceCharacteristics(sqlite3_file *pFile){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsDeviceCharacteristics(p->pReal);
}
/*
** Write data to an writecrash-file.
*/
static int writecrashWrite(
sqlite3_file *pFile,
const void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
devsym_file *p = (devsym_file *)pFile;
if( g.nWriteCrash>0 ){
g.nWriteCrash--;
if( g.nWriteCrash==0 ) abort();
}
return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
}
/*
** Open an writecrash file handle.
*/
static int writecrashOpen(
sqlite3_vfs *pVfs,
const char *zName,
sqlite3_file *pFile,
int flags,
int *pOutFlags
){
static sqlite3_io_methods writecrash_io_methods = {
2, /* iVersion */
devsymClose, /* xClose */
devsymRead, /* xRead */
writecrashWrite, /* xWrite */
devsymTruncate, /* xTruncate */
devsymSync, /* xSync */
devsymFileSize, /* xFileSize */
devsymLock, /* xLock */
devsymUnlock, /* xUnlock */
devsymCheckReservedLock, /* xCheckReservedLock */
devsymFileControl, /* xFileControl */
writecrashSectorSize, /* xSectorSize */
writecrashDeviceCharacteristics, /* xDeviceCharacteristics */
devsymShmMap, /* xShmMap */
devsymShmLock, /* xShmLock */
devsymShmBarrier, /* xShmBarrier */
devsymShmUnmap /* xShmUnmap */
};
int rc;
devsym_file *p = (devsym_file *)pFile;
p->pReal = (sqlite3_file *)&p[1];
rc = sqlite3OsOpen(g.pVfs, zName, p->pReal, flags, pOutFlags);
if( p->pReal->pMethods ){
pFile->pMethods = &writecrash_io_methods;
}
return rc;
}
static sqlite3_vfs devsym_vfs = {
2, /* iVersion */
sizeof(devsym_file), /* szOsFile */
DEVSYM_MAX_PATHNAME, /* mxPathname */
0, /* pNext */
DEVSYM_VFS_NAME, /* zName */
0, /* pAppData */
devsymOpen, /* xOpen */
devsymDelete, /* xDelete */
devsymAccess, /* xAccess */
devsymFullPathname, /* xFullPathname */
#ifndef SQLITE_OMIT_LOAD_EXTENSION
devsymDlOpen, /* xDlOpen */
devsymDlError, /* xDlError */
devsymDlSym, /* xDlSym */
devsymDlClose, /* xDlClose */
#else
0, /* xDlOpen */
0, /* xDlError */
0, /* xDlSym */
0, /* xDlClose */
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
devsymRandomness, /* xRandomness */
devsymSleep, /* xSleep */
devsymCurrentTime, /* xCurrentTime */
0, /* xGetLastError */
0 /* xCurrentTimeInt64 */
};
static sqlite3_vfs writecrash_vfs = {
2, /* iVersion */
sizeof(devsym_file), /* szOsFile */
DEVSYM_MAX_PATHNAME, /* mxPathname */
0, /* pNext */
WRITECRASH_NAME, /* zName */
0, /* pAppData */
writecrashOpen, /* xOpen */
devsymDelete, /* xDelete */
devsymAccess, /* xAccess */
devsymFullPathname, /* xFullPathname */
#ifndef SQLITE_OMIT_LOAD_EXTENSION
devsymDlOpen, /* xDlOpen */
devsymDlError, /* xDlError */
devsymDlSym, /* xDlSym */
devsymDlClose, /* xDlClose */
#else
0, /* xDlOpen */
0, /* xDlError */
0, /* xDlSym */
0, /* xDlClose */
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
devsymRandomness, /* xRandomness */
devsymSleep, /* xSleep */
devsymCurrentTime, /* xCurrentTime */
0, /* xGetLastError */
0 /* xCurrentTimeInt64 */
};
/*
** This procedure registers the devsym vfs with SQLite. If the argument is
** true, the devsym vfs becomes the new default vfs. It is the only publicly
** available function in this file.
*/
void devsym_register(int iDeviceChar, int iSectorSize){
if( g.pVfs==0 ){
g.pVfs = sqlite3_vfs_find(0);
devsym_vfs.szOsFile += g.pVfs->szOsFile;
writecrash_vfs.szOsFile += g.pVfs->szOsFile;
sqlite3_vfs_register(&devsym_vfs, 0);
sqlite3_vfs_register(&writecrash_vfs, 0);
}
if( iDeviceChar>=0 ){
g.iDeviceChar = iDeviceChar;
}else{
g.iDeviceChar = 0;
}
if( iSectorSize>=0 ){
g.iSectorSize = iSectorSize;
}else{
g.iSectorSize = 512;
}
}
void devsym_unregister(){
sqlite3_vfs_unregister(&devsym_vfs);
g.pVfs = 0;
g.iDeviceChar = 0;
g.iSectorSize = 0;
}
void devsym_crash_on_write(int nWrite){
if( g.pVfs==0 ){
g.pVfs = sqlite3_vfs_find(0);
devsym_vfs.szOsFile += g.pVfs->szOsFile;
writecrash_vfs.szOsFile += g.pVfs->szOsFile;
sqlite3_vfs_register(&devsym_vfs, 0);
sqlite3_vfs_register(&writecrash_vfs, 0);
}
g.nWriteCrash = nWrite;
}
#endif