15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 2010 May 05 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The author disclaims copyright to this source code. In place of 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** a legal notice, here is a blessing: 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** May you do good and not evil. 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** May you find forgiveness for yourself and forgive others. 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** May you share freely, never taking more than you give. 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)****************************************************************************** 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if SQLITE_TEST /* This file is used for testing only */ 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This file contains the implementation of the Tcl [testvfs] command, 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** used to create SQLite VFS implementations with various properties and 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** instrumentation to support testing SQLite. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** testvfs VFSNAME ?OPTIONS? 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Available options are: 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** -noshm BOOLEAN (True to omit shm methods. Default false) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** -default BOOLEAN (True to make the vfs default. Default false) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** -szosfile INTEGER (Value for sqlite3_vfs.szOsFile) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** -mxpathname INTEGER (Value for sqlite3_vfs.mxPathname) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** -iversion INTEGER (Value for sqlite3_vfs.iVersion) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sqlite3.h" 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sqliteInt.h" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct Testvfs Testvfs; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct TestvfsShm TestvfsShm; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct TestvfsBuffer TestvfsBuffer; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct TestvfsFile TestvfsFile; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct TestvfsFd TestvfsFd; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** An open file handle. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct TestvfsFile { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file base; /* Base class. Must be first */ 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *pFd; /* File data */ 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define tvfsGetFd(pFile) (((TestvfsFile *)pFile)->pFd) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct TestvfsFd { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_vfs *pVfs; /* The VFS */ 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *zFilename; /* Filename as passed to xOpen() */ 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pReal; /* The real, underlying file descriptor */ 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *pShmId; /* Shared memory id for Tcl callbacks */ 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsBuffer *pShm; /* Shared memory buffer */ 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) u32 excllock; /* Mask of exclusive locks */ 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) u32 sharedlock; /* Mask of shared locks */ 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *pNext; /* Next handle opened on the same file */ 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define FAULT_INJECT_NONE 0 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define FAULT_INJECT_TRANSIENT 1 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define FAULT_INJECT_PERSISTENT 2 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct TestFaultInject TestFaultInject; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct TestFaultInject { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iCnt; /* Remaining calls before fault injection */ 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int eFault; /* A FAULT_INJECT_* value */ 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nFail; /* Number of faults injected */ 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** An instance of this structure is allocated for each VFS created. The 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** sqlite3_vfs.pAppData field of the VFS structure registered with SQLite 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** is set to point to it. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct Testvfs { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *zName; /* Name of this VFS */ 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_vfs *pParent; /* The VFS to use for file IO */ 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_vfs *pVfs; /* The testvfs registered with SQLite */ 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Interp *interp; /* Interpreter to run script in */ 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *pScript; /* Script to execute */ 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nScript; /* Number of elements in array apScript */ 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj **apScript; /* Array version of pScript */ 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsBuffer *pBuffer; /* List of shared buffers */ 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int isNoshm; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int mask; /* Mask controlling [script] and [ioerr] */ 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestFaultInject ioerr_err; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestFaultInject full_err; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestFaultInject cantopen_err; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if 0 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iIoerrCnt; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ioerr; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nIoerrFail; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iFullCnt; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int fullerr; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nFullFail; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iDevchar; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iSectorsize; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The Testvfs.mask variable is set to a combination of the following. 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** If a bit is clear in Testvfs.mask, then calls made by SQLite to the 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** corresponding VFS method is ignored for purposes of: 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** + Simulating IO errors, and 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** + Invoking the Tcl callback script. 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TESTVFS_SHMOPEN_MASK 0x00000001 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TESTVFS_SHMLOCK_MASK 0x00000010 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TESTVFS_SHMMAP_MASK 0x00000020 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TESTVFS_SHMBARRIER_MASK 0x00000040 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TESTVFS_SHMCLOSE_MASK 0x00000080 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TESTVFS_OPEN_MASK 0x00000100 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TESTVFS_SYNC_MASK 0x00000200 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TESTVFS_DELETE_MASK 0x00000400 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TESTVFS_CLOSE_MASK 0x00000800 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TESTVFS_WRITE_MASK 0x00001000 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TESTVFS_TRUNCATE_MASK 0x00002000 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TESTVFS_ACCESS_MASK 0x00004000 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TESTVFS_ALL_MASK 0x00007FFF 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TESTVFS_MAX_PAGES 1024 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** A shared-memory buffer. There is one of these objects for each shared 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** memory region opened by clients. If two clients open the same file, 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** there are two TestvfsFile structures but only one TestvfsBuffer structure. 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct TestvfsBuffer { 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *zFile; /* Associated file name */ 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int pgsz; /* Page size */ 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) u8 *aPage[TESTVFS_MAX_PAGES]; /* Array of ckalloc'd pages */ 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *pFile; /* List of open handles */ 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsBuffer *pNext; /* Next in linked list of all buffers */ 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define PARENTVFS(x) (((Testvfs *)((x)->pAppData))->pParent) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TESTVFS_MAX_ARGS 12 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Method declarations for TestvfsFile. 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsClose(sqlite3_file*); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsTruncate(sqlite3_file*, sqlite3_int64 size); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsSync(sqlite3_file*, int flags); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsFileSize(sqlite3_file*, sqlite3_int64 *pSize); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsLock(sqlite3_file*, int); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsUnlock(sqlite3_file*, int); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsCheckReservedLock(sqlite3_file*, int *); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsFileControl(sqlite3_file*, int op, void *pArg); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsSectorSize(sqlite3_file*); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsDeviceCharacteristics(sqlite3_file*); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Method declarations for tvfs_vfs. 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsDelete(sqlite3_vfs*, const char *zName, int syncDir); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsAccess(sqlite3_vfs*, const char *zName, int flags, int *); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef SQLITE_OMIT_LOAD_EXTENSION 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void *tvfsDlOpen(sqlite3_vfs*, const char *zFilename); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void tvfsDlError(sqlite3_vfs*, int nByte, char *zErrMsg); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void (*tvfsDlSym(sqlite3_vfs*,void*, const char *zSymbol))(void); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void tvfsDlClose(sqlite3_vfs*, void*); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* SQLITE_OMIT_LOAD_EXTENSION */ 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsRandomness(sqlite3_vfs*, int nByte, char *zOut); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsSleep(sqlite3_vfs*, int microseconds); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsCurrentTime(sqlite3_vfs*, double*); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsShmOpen(sqlite3_file*); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsShmLock(sqlite3_file*, int , int, int); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsShmMap(sqlite3_file*,int,int,int, void volatile **); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void tvfsShmBarrier(sqlite3_file*); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsShmUnmap(sqlite3_file*, int); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static sqlite3_io_methods tvfs_io_methods = { 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2, /* iVersion */ 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsClose, /* xClose */ 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsRead, /* xRead */ 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsWrite, /* xWrite */ 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsTruncate, /* xTruncate */ 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsSync, /* xSync */ 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsFileSize, /* xFileSize */ 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsLock, /* xLock */ 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsUnlock, /* xUnlock */ 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsCheckReservedLock, /* xCheckReservedLock */ 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsFileControl, /* xFileControl */ 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsSectorSize, /* xSectorSize */ 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsDeviceCharacteristics, /* xDeviceCharacteristics */ 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsShmMap, /* xShmMap */ 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsShmLock, /* xShmLock */ 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsShmBarrier, /* xShmBarrier */ 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsShmUnmap /* xShmUnmap */ 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsResultCode(Testvfs *p, int *pRc){ 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct errcode { 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int eCode; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *zCode; 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } aCode[] = { 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { SQLITE_OK, "SQLITE_OK" }, 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { SQLITE_ERROR, "SQLITE_ERROR" }, 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { SQLITE_IOERR, "SQLITE_IOERR" }, 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { SQLITE_LOCKED, "SQLITE_LOCKED" }, 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { SQLITE_BUSY, "SQLITE_BUSY" }, 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *z; 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) z = Tcl_GetStringResult(p->interp); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(i=0; i<ArraySize(aCode); i++){ 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( 0==strcmp(z, aCode[i].zCode) ){ 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *pRc = aCode[i].eCode; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsInjectFault(TestFaultInject *p){ 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ret = 0; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->eFault ){ 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->iCnt--; 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->iCnt==0 || (p->iCnt<0 && p->eFault==FAULT_INJECT_PERSISTENT ) ){ 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ret = 1; 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->nFail++; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ret; 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsInjectIoerr(Testvfs *p){ 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return tvfsInjectFault(&p->ioerr_err); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsInjectFullerr(Testvfs *p){ 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return tvfsInjectFault(&p->full_err); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsInjectCantopenerr(Testvfs *p){ 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return tvfsInjectFault(&p->cantopen_err); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void tvfsExecTcl( 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Testvfs *p, 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *zMethod, 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *arg1, 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *arg2, 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *arg3 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc; /* Return code from Tcl_EvalObj() */ 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nArg; /* Elements in eval'd list */ 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nScript; 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj ** ap; 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert( p->pScript ); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( !p->apScript ){ 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nByte; 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( TCL_OK!=Tcl_ListObjGetElements(p->interp, p->pScript, &nScript, &ap) ){ 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_BackgroundError(p->interp); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ResetResult(p->interp); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->nScript = nScript; 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nByte = (nScript+TESTVFS_MAX_ARGS)*sizeof(Tcl_Obj *); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->apScript = (Tcl_Obj **)ckalloc(nByte); 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(p->apScript, 0, nByte); 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(i=0; i<nScript; i++){ 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->apScript[i] = ap[i]; 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->apScript[p->nScript] = Tcl_NewStringObj(zMethod, -1); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->apScript[p->nScript+1] = arg1; 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->apScript[p->nScript+2] = arg2; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->apScript[p->nScript+3] = arg3; 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(nArg=p->nScript; p->apScript[nArg]; nArg++){ 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_IncrRefCount(p->apScript[nArg]); 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = Tcl_EvalObjv(p->interp, nArg, p->apScript, TCL_EVAL_GLOBAL); 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc!=TCL_OK ){ 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_BackgroundError(p->interp); 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ResetResult(p->interp); 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(nArg=p->nScript; p->apScript[nArg]; nArg++){ 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_DecrRefCount(p->apScript[nArg]); 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->apScript[nArg] = 0; 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Close an tvfs-file. 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsClose(sqlite3_file *pFile){ 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc; 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFile *pTestfile = (TestvfsFile *)pFile; 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *pFd = pTestfile->pFd; 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->pScript && p->mask&TESTVFS_CLOSE_MASK ){ 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsExecTcl(p, "xClose", 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pFd->pShmId ){ 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_DecrRefCount(pFd->pShmId); 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFd->pShmId = 0; 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pFile->pMethods ){ 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ckfree((char *)pFile->pMethods); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = sqlite3OsClose(pFd->pReal); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ckfree((char *)pFd); 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pTestfile->pFd = 0; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rc; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Read data from an tvfs-file. 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsRead( 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pFile, 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *zBuf, 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iAmt, 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite_int64 iOfst 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *p = tvfsGetFd(pFile); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst); 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Write data to an tvfs-file. 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsWrite( 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pFile, 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void *zBuf, 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iAmt, 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite_int64 iOfst 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc = SQLITE_OK; 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *pFd = tvfsGetFd(pFile); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->pScript && p->mask&TESTVFS_WRITE_MASK ){ 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsExecTcl(p, "xWrite", 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsResultCode(p, &rc); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc==SQLITE_OK && tvfsInjectFullerr(p) ){ 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = SQLITE_FULL; 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc==SQLITE_OK && p->mask&TESTVFS_WRITE_MASK && tvfsInjectIoerr(p) ){ 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = SQLITE_IOERR; 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc==SQLITE_OK ){ 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = sqlite3OsWrite(pFd->pReal, zBuf, iAmt, iOfst); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rc; 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Truncate an tvfs-file. 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){ 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc = SQLITE_OK; 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *pFd = tvfsGetFd(pFile); 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->pScript && p->mask&TESTVFS_TRUNCATE_MASK ){ 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsExecTcl(p, "xTruncate", 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ); 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsResultCode(p, &rc); 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc==SQLITE_OK ){ 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = sqlite3OsTruncate(pFd->pReal, size); 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rc; 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Sync an tvfs-file. 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsSync(sqlite3_file *pFile, int flags){ 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc = SQLITE_OK; 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *pFd = tvfsGetFd(pFile); 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->pScript && p->mask&TESTVFS_SYNC_MASK ){ 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *zFlags; 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch( flags ){ 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SQLITE_SYNC_NORMAL: 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zFlags = "normal"; 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SQLITE_SYNC_FULL: 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zFlags = "full"; 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SQLITE_SYNC_NORMAL|SQLITE_SYNC_DATAONLY: 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zFlags = "normal|dataonly"; 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SQLITE_SYNC_FULL|SQLITE_SYNC_DATAONLY: 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zFlags = "full|dataonly"; 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(0); 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsExecTcl(p, "xSync", 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_NewStringObj(zFlags, -1) 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ); 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsResultCode(p, &rc); 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc==SQLITE_OK && tvfsInjectFullerr(p) ) rc = SQLITE_FULL; 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc==SQLITE_OK ){ 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = sqlite3OsSync(pFd->pReal, flags); 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rc; 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return the current file-size of an tvfs-file. 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *p = tvfsGetFd(pFile); 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sqlite3OsFileSize(p->pReal, pSize); 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Lock an tvfs-file. 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsLock(sqlite3_file *pFile, int eLock){ 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *p = tvfsGetFd(pFile); 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sqlite3OsLock(p->pReal, eLock); 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Unlock an tvfs-file. 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsUnlock(sqlite3_file *pFile, int eLock){ 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *p = tvfsGetFd(pFile); 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sqlite3OsUnlock(p->pReal, eLock); 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Check if another file-handle holds a RESERVED lock on an tvfs-file. 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){ 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *p = tvfsGetFd(pFile); 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sqlite3OsCheckReservedLock(p->pReal, pResOut); 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** File control method. For custom operations on an tvfs-file. 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){ 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *p = tvfsGetFd(pFile); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sqlite3OsFileControl(p->pReal, op, pArg); 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return the sector-size in bytes for an tvfs-file. 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsSectorSize(sqlite3_file *pFile){ 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *pFd = tvfsGetFd(pFile); 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->iSectorsize>=0 ){ 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return p->iSectorsize; 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sqlite3OsSectorSize(pFd->pReal); 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return the device characteristic flags supported by an tvfs-file. 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsDeviceCharacteristics(sqlite3_file *pFile){ 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *pFd = tvfsGetFd(pFile); 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->iDevchar>=0 ){ 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return p->iDevchar; 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sqlite3OsDeviceCharacteristics(pFd->pReal); 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Open an tvfs file handle. 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsOpen( 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_vfs *pVfs, 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *zName, 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pFile, 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int flags, 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int *pOutFlags 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc; 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFile *pTestfile = (TestvfsFile *)pFile; 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *pFd; 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *pId = 0; 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Testvfs *p = (Testvfs *)pVfs->pAppData; 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFd = (TestvfsFd *)ckalloc(sizeof(TestvfsFd) + PARENTVFS(pVfs)->szOsFile); 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(pFd, 0, sizeof(TestvfsFd) + PARENTVFS(pVfs)->szOsFile); 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFd->pShm = 0; 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFd->pShmId = 0; 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFd->zFilename = zName; 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFd->pVfs = pVfs; 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFd->pReal = (sqlite3_file *)&pFd[1]; 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(pTestfile, 0, sizeof(TestvfsFile)); 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pTestfile->pFd = pFd; 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Evaluate the Tcl script: 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** SCRIPT xOpen FILENAME 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** If the script returns an SQLite error code other than SQLITE_OK, an 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** error is returned to the caller. If it returns SQLITE_OK, the new 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** connection is named "anon". Otherwise, the value returned by the 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** script is used as the connection name. 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ResetResult(p->interp); 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->pScript && p->mask&TESTVFS_OPEN_MASK ){ 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsExecTcl(p, "xOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0); 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( tvfsResultCode(p, &rc) ){ 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc!=SQLITE_OK ) return rc; 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }else{ 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pId = Tcl_GetObjResult(p->interp); 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( (p->mask&TESTVFS_OPEN_MASK) && tvfsInjectIoerr(p) ) return SQLITE_IOERR; 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( tvfsInjectCantopenerr(p) ) return SQLITE_CANTOPEN; 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( tvfsInjectFullerr(p) ) return SQLITE_FULL; 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( !pId ){ 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pId = Tcl_NewStringObj("anon", -1); 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_IncrRefCount(pId); 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFd->pShmId = pId; 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ResetResult(p->interp); 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = sqlite3OsOpen(PARENTVFS(pVfs), zName, pFd->pReal, flags, pOutFlags); 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pFd->pReal->pMethods ){ 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_io_methods *pMethods; 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nByte; 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pVfs->iVersion>1 ){ 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nByte = sizeof(sqlite3_io_methods); 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }else{ 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nByte = offsetof(sqlite3_io_methods, xShmMap); 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pMethods = (sqlite3_io_methods *)ckalloc(nByte); 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(pMethods, &tvfs_io_methods, nByte); 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pMethods->iVersion = pVfs->iVersion; 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pVfs->iVersion>1 && ((Testvfs *)pVfs->pAppData)->isNoshm ){ 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pMethods->xShmUnmap = 0; 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pMethods->xShmLock = 0; 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pMethods->xShmBarrier = 0; 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pMethods->xShmMap = 0; 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFile->pMethods = pMethods; 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rc; 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Delete the file located at zPath. If the dirSync argument is true, 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** ensure the file-system modifications are synced to disk before 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** returning. 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc = SQLITE_OK; 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Testvfs *p = (Testvfs *)pVfs->pAppData; 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->pScript && p->mask&TESTVFS_DELETE_MASK ){ 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsExecTcl(p, "xDelete", 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_NewStringObj(zPath, -1), Tcl_NewIntObj(dirSync), 0 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ); 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsResultCode(p, &rc); 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc==SQLITE_OK ){ 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = sqlite3OsDelete(PARENTVFS(pVfs), zPath, dirSync); 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rc; 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Test for access permissions. Return true if the requested permission 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** is available, or false otherwise. 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsAccess( 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_vfs *pVfs, 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *zPath, 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int flags, 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int *pResOut 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Testvfs *p = (Testvfs *)pVfs->pAppData; 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->pScript && p->mask&TESTVFS_ACCESS_MASK ){ 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc; 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *zArg = 0; 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( flags==SQLITE_ACCESS_EXISTS ) zArg = "SQLITE_ACCESS_EXISTS"; 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( flags==SQLITE_ACCESS_READWRITE ) zArg = "SQLITE_ACCESS_READWRITE"; 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( flags==SQLITE_ACCESS_READ ) zArg = "SQLITE_ACCESS_READ"; 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsExecTcl(p, "xAccess", 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_NewStringObj(zPath, -1), Tcl_NewStringObj(zArg, -1), 0 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ); 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( tvfsResultCode(p, &rc) ){ 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc!=SQLITE_OK ) return rc; 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }else{ 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Interp *interp = p->interp; 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( TCL_OK==Tcl_GetBooleanFromObj(0, Tcl_GetObjResult(interp), pResOut) ){ 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SQLITE_OK; 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sqlite3OsAccess(PARENTVFS(pVfs), zPath, flags, pResOut); 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Populate buffer zOut with the full canonical pathname corresponding 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** to the pathname in zPath. zOut is guaranteed to point to a buffer 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** of at least (DEVSYM_MAX_PATHNAME+1) bytes. 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsFullPathname( 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_vfs *pVfs, 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *zPath, 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nOut, 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *zOut 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sqlite3OsFullPathname(PARENTVFS(pVfs), zPath, nOut, zOut); 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef SQLITE_OMIT_LOAD_EXTENSION 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Open the dynamic library located at zPath and return a handle. 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void *tvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){ 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sqlite3OsDlOpen(PARENTVFS(pVfs), zPath); 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Populate the buffer zErrMsg (size nByte bytes) with a human readable 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** utf-8 string describing the most recent error encountered associated 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** with dynamic libraries. 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void tvfsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3OsDlError(PARENTVFS(pVfs), nByte, zErrMsg); 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return a pointer to the symbol zSymbol in the dynamic library pHandle. 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void (*tvfsDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sqlite3OsDlSym(PARENTVFS(pVfs), p, zSym); 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Close the dynamic library handle pHandle. 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void tvfsDlClose(sqlite3_vfs *pVfs, void *pHandle){ 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3OsDlClose(PARENTVFS(pVfs), pHandle); 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* SQLITE_OMIT_LOAD_EXTENSION */ 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Populate the buffer pointed to by zBufOut with nByte bytes of 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** random data. 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sqlite3OsRandomness(PARENTVFS(pVfs), nByte, zBufOut); 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Sleep for nMicro microseconds. Return the number of microseconds 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** actually slept. 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsSleep(sqlite3_vfs *pVfs, int nMicro){ 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sqlite3OsSleep(PARENTVFS(pVfs), nMicro); 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return the current time as a Julian Day number in *pTimeOut. 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return PARENTVFS(pVfs)->xCurrentTime(PARENTVFS(pVfs), pTimeOut); 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsShmOpen(sqlite3_file *pFile){ 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Testvfs *p; 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc = SQLITE_OK; /* Return code */ 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsBuffer *pBuffer; /* Buffer to open connection to */ 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *pFd; /* The testvfs file structure */ 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFd = tvfsGetFd(pFile); 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = (Testvfs *)pFd->pVfs->pAppData; 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert( pFd->pShmId && pFd->pShm==0 && pFd->pNext==0 ); 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Evaluate the Tcl script: 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** SCRIPT xShmOpen FILENAME 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ResetResult(p->interp); 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->pScript && p->mask&TESTVFS_SHMOPEN_MASK ){ 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsExecTcl(p, "xShmOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0); 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( tvfsResultCode(p, &rc) ){ 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc!=SQLITE_OK ) return rc; 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert( rc==SQLITE_OK ); 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->mask&TESTVFS_SHMOPEN_MASK && tvfsInjectIoerr(p) ){ 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SQLITE_IOERR; 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Search for a TestvfsBuffer. Create a new one if required. */ 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(pBuffer=p->pBuffer; pBuffer; pBuffer=pBuffer->pNext){ 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( 0==strcmp(pFd->zFilename, pBuffer->zFile) ) break; 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( !pBuffer ){ 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nByte = sizeof(TestvfsBuffer) + strlen(pFd->zFilename) + 1; 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pBuffer = (TestvfsBuffer *)ckalloc(nByte); 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(pBuffer, 0, nByte); 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pBuffer->zFile = (char *)&pBuffer[1]; 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strcpy(pBuffer->zFile, pFd->zFilename); 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pBuffer->pNext = p->pBuffer; 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->pBuffer = pBuffer; 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Connect the TestvfsBuffer to the new TestvfsShm handle and return. */ 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFd->pNext = pBuffer->pFile; 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pBuffer->pFile = pFd; 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFd->pShm = pBuffer; 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SQLITE_OK; 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void tvfsAllocPage(TestvfsBuffer *p, int iPage, int pgsz){ 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert( iPage<TESTVFS_MAX_PAGES ); 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->aPage[iPage]==0 ){ 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->aPage[iPage] = (u8 *)ckalloc(pgsz); 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(p->aPage[iPage], 0, pgsz); 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->pgsz = pgsz; 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsShmMap( 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pFile, /* Handle open on database file */ 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iPage, /* Page to retrieve */ 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int pgsz, /* Size of pages */ 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int isWrite, /* True to extend file if necessary */ 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void volatile **pp /* OUT: Mapped memory */ 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc = SQLITE_OK; 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *pFd = tvfsGetFd(pFile); 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( 0==pFd->pShm ){ 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = tvfsShmOpen(pFile); 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc!=SQLITE_OK ){ 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rc; 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->pScript && p->mask&TESTVFS_SHMMAP_MASK ){ 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *pArg = Tcl_NewObj(); 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_IncrRefCount(pArg); 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(iPage)); 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(pgsz)); 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(isWrite)); 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsExecTcl(p, "xShmMap", 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, pArg 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ); 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsResultCode(p, &rc); 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_DecrRefCount(pArg); 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc==SQLITE_OK && p->mask&TESTVFS_SHMMAP_MASK && tvfsInjectIoerr(p) ){ 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = SQLITE_IOERR; 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc==SQLITE_OK && isWrite && !pFd->pShm->aPage[iPage] ){ 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsAllocPage(pFd->pShm, iPage, pgsz); 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *pp = (void volatile *)pFd->pShm->aPage[iPage]; 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rc; 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsShmLock( 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pFile, 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ofst, 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int n, 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int flags 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc = SQLITE_OK; 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *pFd = tvfsGetFd(pFile); 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nLock; 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char zLock[80]; 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->pScript && p->mask&TESTVFS_SHMLOCK_MASK ){ 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_snprintf(sizeof(zLock), zLock, "%d %d", ofst, n); 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nLock = strlen(zLock); 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( flags & SQLITE_SHM_LOCK ){ 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strcpy(&zLock[nLock], " lock"); 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }else{ 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strcpy(&zLock[nLock], " unlock"); 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nLock += strlen(&zLock[nLock]); 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( flags & SQLITE_SHM_SHARED ){ 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strcpy(&zLock[nLock], " shared"); 8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }else{ 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strcpy(&zLock[nLock], " exclusive"); 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsExecTcl(p, "xShmLock", 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_NewStringObj(zLock, -1) 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ); 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsResultCode(p, &rc); 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc==SQLITE_OK && p->mask&TESTVFS_SHMLOCK_MASK && tvfsInjectIoerr(p) ){ 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = SQLITE_IOERR; 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc==SQLITE_OK ){ 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int isLock = (flags & SQLITE_SHM_LOCK); 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int isExcl = (flags & SQLITE_SHM_EXCLUSIVE); 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) u32 mask = (((1<<n)-1) << ofst); 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( isLock ){ 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *p2; 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(p2=pFd->pShm->pFile; p2; p2=p2->pNext){ 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p2==pFd ) continue; 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( (p2->excllock&mask) || (isExcl && p2->sharedlock&mask) ){ 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rc = SQLITE_BUSY; 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( rc==SQLITE_OK ){ 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( isExcl ) pFd->excllock |= mask; 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( !isExcl ) pFd->sharedlock |= mask; 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }else{ 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( isExcl ) pFd->excllock &= (~mask); 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( !isExcl ) pFd->sharedlock &= (~mask); 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rc; 8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void tvfsShmBarrier(sqlite3_file *pFile){ 8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *pFd = tvfsGetFd(pFile); 8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){ 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsExecTcl(p, "xShmBarrier", 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ); 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int tvfsShmUnmap( 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_file *pFile, 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int deleteFlag 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rc = SQLITE_OK; 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd *pFd = tvfsGetFd(pFile); 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsBuffer *pBuffer = pFd->pShm; 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsFd **ppFd; 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( !pBuffer ) return SQLITE_OK; 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert( pFd->pShmId && pFd->pShm ); 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->pScript && p->mask&TESTVFS_SHMCLOSE_MASK ){ 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsExecTcl(p, "xShmUnmap", 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ); 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsResultCode(p, &rc); 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(ppFd=&pBuffer->pFile; *ppFd!=pFd; ppFd=&((*ppFd)->pNext)); 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert( (*ppFd)==pFd ); 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *ppFd = pFd->pNext; 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFd->pNext = 0; 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pBuffer->pFile==0 ){ 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsBuffer **pp; 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(pp=&p->pBuffer; *pp!=pBuffer; pp=&((*pp)->pNext)); 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *pp = (*pp)->pNext; 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(i=0; pBuffer->aPage[i]; i++){ 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ckfree((char *)pBuffer->aPage[i]); 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ckfree((char *)pBuffer); 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pFd->pShm = 0; 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rc; 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int testvfs_obj_cmd( 9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ClientData cd, 9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Interp *interp, 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int objc, 9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *CONST objv[] 9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Testvfs *p = (Testvfs *)cd; 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum DB_enum { 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT, 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CMD_DEVCHAR, CMD_SECTORSIZE, CMD_FULLERR, CMD_CANTOPENERR 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct TestvfsSubcmd { 9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *zName; 9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum DB_enum eCmd; 9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } aSubcmd[] = { 9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "shm", CMD_SHM }, 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "delete", CMD_DELETE }, 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "filter", CMD_FILTER }, 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "ioerr", CMD_IOERR }, 9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "fullerr", CMD_FULLERR }, 9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "cantopenerr", CMD_CANTOPENERR }, 9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "script", CMD_SCRIPT }, 9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "devchar", CMD_DEVCHAR }, 9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "sectorsize", CMD_SECTORSIZE }, 9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 0, 0 } 9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( objc<2 ){ 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); 9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( Tcl_GetIndexFromObjStruct( 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) interp, objv[1], aSubcmd, sizeof(aSubcmd[0]), "subcommand", 0, &i) 9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ){ 9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ResetResult(interp); 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch( aSubcmd[i].eCmd ){ 9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case CMD_SHM: { 9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *pObj; 9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestvfsBuffer *pBuffer; 9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *zName; 9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( objc!=3 && objc!=4 ){ 9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_WrongNumArgs(interp, 2, objv, "FILE ?VALUE?"); 9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zName = ckalloc(p->pParent->mxPathname); 9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->pParent->xFullPathname( 9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->pParent, Tcl_GetString(objv[2]), 9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->pParent->mxPathname, zName 9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ); 9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(pBuffer=p->pBuffer; pBuffer; pBuffer=pBuffer->pNext){ 9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( 0==strcmp(pBuffer->zFile, zName) ) break; 9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ckfree(zName); 9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( !pBuffer ){ 9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_AppendResult(interp, "no such file: ", Tcl_GetString(objv[2]), 0); 9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( objc==4 ){ 10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int n; 10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) u8 *a = Tcl_GetByteArrayFromObj(objv[3], &n); 10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int pgsz = pBuffer->pgsz; 10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pgsz==0 ) pgsz = 65536; 10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(i=0; i*pgsz<n; i++){ 10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nByte = pgsz; 10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsAllocPage(pBuffer, i, pgsz); 10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( n-i*pgsz<pgsz ){ 10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nByte = n; 10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(pBuffer->aPage[i], &a[i*pgsz], nByte); 10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pObj = Tcl_NewObj(); 10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(i=0; pBuffer->aPage[i]; i++){ 10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int pgsz = pBuffer->pgsz; 10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( pgsz==0 ) pgsz = 65536; 10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_AppendObjToObj(pObj, Tcl_NewByteArrayObj(pBuffer->aPage[i], pgsz)); 10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_SetObjResult(interp, pObj); 10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case CMD_FILTER: { 10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static struct VfsMethod { 10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *zName; 10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int mask; 10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } vfsmethod [] = { 10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "xShmOpen", TESTVFS_SHMOPEN_MASK }, 10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "xShmLock", TESTVFS_SHMLOCK_MASK }, 10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "xShmBarrier", TESTVFS_SHMBARRIER_MASK }, 10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "xShmUnmap", TESTVFS_SHMCLOSE_MASK }, 10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "xShmMap", TESTVFS_SHMMAP_MASK }, 10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "xSync", TESTVFS_SYNC_MASK }, 10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "xDelete", TESTVFS_DELETE_MASK }, 10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "xWrite", TESTVFS_WRITE_MASK }, 10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "xTruncate", TESTVFS_TRUNCATE_MASK }, 10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "xOpen", TESTVFS_OPEN_MASK }, 10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "xClose", TESTVFS_CLOSE_MASK }, 10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "xAccess", TESTVFS_ACCESS_MASK }, 10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj **apElem = 0; 10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nElem = 0; 10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int mask = 0; 10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( objc!=3 ){ 10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_WrongNumArgs(interp, 2, objv, "LIST"); 10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( Tcl_ListObjGetElements(interp, objv[2], &nElem, &apElem) ){ 10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ResetResult(interp); 10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(i=0; i<nElem; i++){ 10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iMethod; 10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *zElem = Tcl_GetString(apElem[i]); 10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(iMethod=0; iMethod<ArraySize(vfsmethod); iMethod++){ 10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( strcmp(zElem, vfsmethod[iMethod].zName)==0 ){ 10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mask |= vfsmethod[iMethod].mask; 10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( iMethod==ArraySize(vfsmethod) ){ 10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_AppendResult(interp, "unknown method: ", zElem, 0); 10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->mask = mask; 10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case CMD_SCRIPT: { 10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( objc==3 ){ 10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nByte; 10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->pScript ){ 10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_DecrRefCount(p->pScript); 10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ckfree((char *)p->apScript); 10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->apScript = 0; 10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->nScript = 0; 10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->pScript = 0; 10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_GetStringFromObj(objv[2], &nByte); 10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( nByte>0 ){ 10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->pScript = Tcl_DuplicateObj(objv[2]); 10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_IncrRefCount(p->pScript); 10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }else if( objc!=2 ){ 10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?"); 10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ResetResult(interp); 10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->pScript ) Tcl_SetObjResult(interp, p->pScript); 10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* 11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** TESTVFS ioerr ?IFAIL PERSIST? 11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** 11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** Where IFAIL is an integer and PERSIST is boolean. 11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case CMD_CANTOPENERR: 11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case CMD_IOERR: 11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case CMD_FULLERR: { 11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestFaultInject *pTest; 11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iRet; 11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch( aSubcmd[i].eCmd ){ 11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case CMD_IOERR: pTest = &p->ioerr_err; break; 11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case CMD_FULLERR: pTest = &p->full_err; break; 11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case CMD_CANTOPENERR: pTest = &p->cantopen_err; break; 11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: assert(0); 11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iRet = pTest->nFail; 11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pTest->nFail = 0; 11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pTest->eFault = 0; 11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pTest->iCnt = 0; 11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( objc==4 ){ 11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iCnt, iPersist; 11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iCnt) 11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) || TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &iPersist) 11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ){ 11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pTest->eFault = iPersist?FAULT_INJECT_PERSISTENT:FAULT_INJECT_TRANSIENT; 11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pTest->iCnt = iCnt; 11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }else if( objc!=2 ){ 11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_WrongNumArgs(interp, 2, objv, "?CNT PERSIST?"); 11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_SetObjResult(interp, Tcl_NewIntObj(iRet)); 11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case CMD_DELETE: { 11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_DeleteCommand(interp, Tcl_GetString(objv[0])); 11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case CMD_DEVCHAR: { 11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct DeviceFlag { 11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *zName; 11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iValue; 11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } aFlag[] = { 11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "default", -1 }, 11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "atomic", SQLITE_IOCAP_ATOMIC }, 11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "atomic512", SQLITE_IOCAP_ATOMIC512 }, 11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "atomic1k", SQLITE_IOCAP_ATOMIC1K }, 11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "atomic2k", SQLITE_IOCAP_ATOMIC2K }, 11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "atomic4k", SQLITE_IOCAP_ATOMIC4K }, 11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "atomic8k", SQLITE_IOCAP_ATOMIC8K }, 11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "atomic16k", SQLITE_IOCAP_ATOMIC16K }, 11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "atomic32k", SQLITE_IOCAP_ATOMIC32K }, 11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "atomic64k", SQLITE_IOCAP_ATOMIC64K }, 11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "sequential", SQLITE_IOCAP_SEQUENTIAL }, 11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "safe_append", SQLITE_IOCAP_SAFE_APPEND }, 11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { "undeletable_when_open", SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN }, 11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 0, 0 } 11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *pRet; 11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iFlag; 11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( objc>3 ){ 11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_WrongNumArgs(interp, 2, objv, "?ATTR-LIST?"); 11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( objc==3 ){ 11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int j; 11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iNew = 0; 11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj **flags = 0; 11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nFlags = 0; 11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( Tcl_ListObjGetElements(interp, objv[2], &nFlags, &flags) ){ 11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(j=0; j<nFlags; j++){ 11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int idx = 0; 11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( Tcl_GetIndexFromObjStruct(interp, flags[j], aFlag, 11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizeof(aFlag[0]), "flag", 0, &idx) 11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ){ 11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( aFlag[idx].iValue<0 && nFlags>1 ){ 11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_AppendResult(interp, "bad flags: ", Tcl_GetString(objv[2]), 0); 11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iNew |= aFlag[idx].iValue; 11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->iDevchar = iNew; 11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pRet = Tcl_NewObj(); 11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(iFlag=0; iFlag<sizeof(aFlag)/sizeof(aFlag[0]); iFlag++){ 12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->iDevchar & aFlag[iFlag].iValue ){ 12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_ListObjAppendElement( 12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) interp, pRet, Tcl_NewStringObj(aFlag[iFlag].zName, -1) 12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ); 12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_SetObjResult(interp, pRet); 12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case CMD_SECTORSIZE: { 12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( objc>3 ){ 12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_WrongNumArgs(interp, 2, objv, "?VALUE?"); 12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( objc==3 ){ 12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iNew = 0; 12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( Tcl_GetIntFromObj(interp, objv[2], &iNew) ){ 12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->iSectorsize = iNew; 12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_SetObjResult(interp, Tcl_NewIntObj(p->iSectorsize)); 12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_OK; 12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void testvfs_obj_del(ClientData cd){ 12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Testvfs *p = (Testvfs *)cd; 12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( p->pScript ) Tcl_DecrRefCount(p->pScript); 12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_vfs_unregister(p->pVfs); 12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ckfree((char *)p->apScript); 12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ckfree((char *)p->pVfs); 12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ckfree((char *)p); 12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Usage: testvfs VFSNAME ?SWITCHES? 12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Switches are: 12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** -noshm BOOLEAN (True to omit shm methods. Default false) 12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** -default BOOLEAN (True to make the vfs default. Default false) 12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This command creates two things when it is invoked: an SQLite VFS, and 12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** a Tcl command. Both are named VFSNAME. The VFS is installed. It is not 12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** installed as the default VFS. 12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The VFS passes all file I/O calls through to the underlying VFS. 12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Whenever the xShmMap method of the VFS 12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** is invoked, the SCRIPT is executed as follows: 12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** SCRIPT xShmMap FILENAME ID 12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The value returned by the invocation of SCRIPT above is interpreted as 12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** an SQLite error code and returned to SQLite. Either a symbolic 12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** "SQLITE_OK" or numeric "0" value may be returned. 12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The contents of the shared-memory buffer associated with a given file 12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** may be read and set using the following command: 12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** VFSNAME shm FILENAME ?NEWVALUE? 12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** When the xShmLock method is invoked by SQLite, the following script is 12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** run: 12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** SCRIPT xShmLock FILENAME ID LOCK 12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** where LOCK is of the form "OFFSET NBYTE lock/unlock shared/exclusive" 12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/ 12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int testvfs_cmd( 12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ClientData cd, 12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Interp *interp, 12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int objc, 12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_Obj *CONST objv[] 12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){ 12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static sqlite3_vfs tvfs_vfs = { 12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2, /* iVersion */ 12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, /* szOsFile */ 12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, /* mxPathname */ 12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, /* pNext */ 12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, /* zName */ 12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, /* pAppData */ 12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsOpen, /* xOpen */ 12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsDelete, /* xDelete */ 12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsAccess, /* xAccess */ 12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsFullPathname, /* xFullPathname */ 12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef SQLITE_OMIT_LOAD_EXTENSION 12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsDlOpen, /* xDlOpen */ 12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsDlError, /* xDlError */ 12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsDlSym, /* xDlSym */ 12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsDlClose, /* xDlClose */ 12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, /* xDlOpen */ 12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, /* xDlError */ 13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, /* xDlSym */ 13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, /* xDlClose */ 13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* SQLITE_OMIT_LOAD_EXTENSION */ 13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsRandomness, /* xRandomness */ 13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsSleep, /* xSleep */ 13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tvfsCurrentTime, /* xCurrentTime */ 13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, /* xGetLastError */ 13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, /* xCurrentTimeInt64 */ 13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Testvfs *p; /* New object */ 13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_vfs *pVfs; /* New VFS */ 13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *zVfs; 13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nByte; /* Bytes of space to allocate at p */ 13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i; 13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int isNoshm = 0; /* True if -noshm is passed */ 13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int isDefault = 0; /* True if -default is passed */ 13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int szOsFile = 0; /* Value passed to -szosfile */ 13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int mxPathname = -1; /* Value passed to -mxpathname */ 13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int iVersion = 2; /* Value passed to -iversion */ 13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( objc<2 || 0!=(objc%2) ) goto bad_args; 13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for(i=2; i<objc; i += 2){ 13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int nSwitch; 13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char *zSwitch; 13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zSwitch = Tcl_GetStringFromObj(objv[i], &nSwitch); 13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( nSwitch>2 && 0==strncmp("-noshm", zSwitch, nSwitch) ){ 13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( Tcl_GetBooleanFromObj(interp, objv[i+1], &isNoshm) ){ 13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if( nSwitch>2 && 0==strncmp("-default", zSwitch, nSwitch) ){ 13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( Tcl_GetBooleanFromObj(interp, objv[i+1], &isDefault) ){ 13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if( nSwitch>2 && 0==strncmp("-szosfile", zSwitch, nSwitch) ){ 13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( Tcl_GetIntFromObj(interp, objv[i+1], &szOsFile) ){ 13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if( nSwitch>2 && 0==strncmp("-mxpathname", zSwitch, nSwitch) ){ 13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( Tcl_GetIntFromObj(interp, objv[i+1], &mxPathname) ){ 13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if( nSwitch>2 && 0==strncmp("-iversion", zSwitch, nSwitch) ){ 13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( Tcl_GetIntFromObj(interp, objv[i+1], &iVersion) ){ 13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else{ 13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bad_args; 13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( szOsFile<sizeof(TestvfsFile) ){ 13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) szOsFile = sizeof(TestvfsFile); 13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zVfs = Tcl_GetString(objv[1]); 13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nByte = sizeof(Testvfs) + strlen(zVfs)+1; 13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = (Testvfs *)ckalloc(nByte); 13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(p, 0, nByte); 13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->iDevchar = -1; 13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->iSectorsize = -1; 13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* Create the new object command before querying SQLite for a default VFS 13705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** to use for 'real' IO operations. This is because creating the new VFS 13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** may delete an existing [testvfs] VFS of the same name. If such a VFS 13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** is currently the default, the new [testvfs] may end up calling the 13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ** methods of a deleted object. 13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_CreateObjCommand(interp, zVfs, testvfs_obj_cmd, p, testvfs_obj_del); 13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->pParent = sqlite3_vfs_find(0); 13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->interp = interp; 13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->zName = (char *)&p[1]; 13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(p->zName, zVfs, strlen(zVfs)+1); 13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pVfs = (sqlite3_vfs *)ckalloc(sizeof(sqlite3_vfs)); 13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(pVfs, &tvfs_vfs, sizeof(sqlite3_vfs)); 13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pVfs->pAppData = (void *)p; 13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pVfs->iVersion = iVersion; 13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pVfs->zName = p->zName; 13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pVfs->mxPathname = p->pParent->mxPathname; 13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if( mxPathname>=0 && mxPathname<pVfs->mxPathname ){ 13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pVfs->mxPathname = mxPathname; 13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pVfs->szOsFile = szOsFile; 13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->pVfs = pVfs; 13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->isNoshm = isNoshm; 13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p->mask = TESTVFS_ALL_MASK; 13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sqlite3_vfs_register(pVfs, isDefault); 13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_OK; 13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bad_args: 14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-default BOOL? ?-mxpathname INT? ?-szosfile INT? ?-iversion INT?"); 14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_ERROR; 14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int Sqlitetestvfs_Init(Tcl_Interp *interp){ 14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Tcl_CreateObjCommand(interp, "testvfs", testvfs_cmd, 0, 0); 14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TCL_OK; 14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1411