Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
test_vfs.c1698 linesDownload Raw Back to src
1/*2** 2010 May 053**4** The author disclaims copyright to this source code.  In place of5** a legal notice, here is a blessing:6**7**    May you do good and not evil.8**    May you find forgiveness for yourself and forgive others.9**    May you share freely, never taking more than you give.10**11******************************************************************************12**13** This file contains the implementation of the Tcl [testvfs] command,14** used to create SQLite VFS implementations with various properties and15** instrumentation to support testing SQLite.16**17**   testvfs VFSNAME ?OPTIONS?18**19** Available options are:20**21**   -noshm      BOOLEAN        (True to omit shm methods. Default false)22**   -default    BOOLEAN        (True to make the vfs default. Default false)23**   -szosfile   INTEGER        (Value for sqlite3_vfs.szOsFile)24**   -mxpathname INTEGER        (Value for sqlite3_vfs.mxPathname)25**   -iversion   INTEGER        (Value for sqlite3_vfs.iVersion)26*/27#if SQLITE_TEST          /* This file is used for testing only */28 29#include "sqlite3.h"30#include "sqliteInt.h"31#include "tclsqlite.h"32 33typedef struct Testvfs Testvfs;34typedef struct TestvfsShm TestvfsShm;35typedef struct TestvfsBuffer TestvfsBuffer;36typedef struct TestvfsFile TestvfsFile;37typedef struct TestvfsFd TestvfsFd;38 39/*40** An open file handle.41*/42struct TestvfsFile {43  sqlite3_file base;              /* Base class.  Must be first */44  TestvfsFd *pFd;                 /* File data */45};46#define tvfsGetFd(pFile) (((TestvfsFile *)pFile)->pFd)47 48struct TestvfsFd {49  sqlite3_vfs *pVfs;              /* The VFS */50  const char *zFilename;          /* Filename as passed to xOpen() */51  sqlite3_file *pReal;            /* The real, underlying file descriptor */52  Tcl_Obj *pShmId;                /* Shared memory id for Tcl callbacks */53 54  TestvfsBuffer *pShm;            /* Shared memory buffer */55  u32 excllock;                   /* Mask of exclusive locks */56  u32 sharedlock;                 /* Mask of shared locks */57  TestvfsFd *pNext;               /* Next handle opened on the same file */58};59 60 61#define FAULT_INJECT_NONE       062#define FAULT_INJECT_TRANSIENT  163#define FAULT_INJECT_PERSISTENT 264 65typedef struct TestFaultInject TestFaultInject;66struct TestFaultInject {67  int iCnt;                       /* Remaining calls before fault injection */68  int eFault;                     /* A FAULT_INJECT_* value */69  int nFail;                      /* Number of faults injected */70};71 72/*73** An instance of this structure is allocated for each VFS created. The74** sqlite3_vfs.pAppData field of the VFS structure registered with SQLite75** is set to point to it.76*/77struct Testvfs {78  char *zName;                    /* Name of this VFS */79  sqlite3_vfs *pParent;           /* The VFS to use for file IO */80  sqlite3_vfs *pVfs;              /* The testvfs registered with SQLite */81  Tcl_Interp *interp;             /* Interpreter to run script in */82  Tcl_Obj *pScript;               /* Script to execute */83  TestvfsBuffer *pBuffer;         /* List of shared buffers */84  int isNoshm;85  int isFullshm;86 87  int mask;                       /* Mask controlling [script] and [ioerr] */88 89  TestFaultInject ioerr_err;90  TestFaultInject full_err;91  TestFaultInject cantopen_err;92 93#if 094  int iIoerrCnt;95  int ioerr;96  int nIoerrFail;97  int iFullCnt;98  int fullerr;99  int nFullFail;100#endif101 102  int iDevchar;103  int iSectorsize;104};105 106/*107** The Testvfs.mask variable is set to a combination of the following.108** If a bit is clear in Testvfs.mask, then calls made by SQLite to the 109** corresponding VFS method is ignored for purposes of:110**111**   + Simulating IO errors, and112**   + Invoking the Tcl callback script.113*/114#define TESTVFS_SHMOPEN_MASK      0x00000001115#define TESTVFS_SHMLOCK_MASK      0x00000010116#define TESTVFS_SHMMAP_MASK       0x00000020117#define TESTVFS_SHMBARRIER_MASK   0x00000040118#define TESTVFS_SHMCLOSE_MASK     0x00000080119 120#define TESTVFS_OPEN_MASK         0x00000100121#define TESTVFS_SYNC_MASK         0x00000200122#define TESTVFS_DELETE_MASK       0x00000400123#define TESTVFS_CLOSE_MASK        0x00000800124#define TESTVFS_WRITE_MASK        0x00001000125#define TESTVFS_TRUNCATE_MASK     0x00002000126#define TESTVFS_ACCESS_MASK       0x00004000127#define TESTVFS_FULLPATHNAME_MASK 0x00008000128#define TESTVFS_READ_MASK         0x00010000129#define TESTVFS_UNLOCK_MASK       0x00020000130#define TESTVFS_LOCK_MASK         0x00040000131#define TESTVFS_CKLOCK_MASK       0x00080000132#define TESTVFS_FCNTL_MASK        0x00100000133#define TESTVFS_SLEEP_MASK        0x00200000134 135#define TESTVFS_ALL_MASK          0x003FFFFF136 137 138#define TESTVFS_MAX_PAGES 1024139 140/*141** A shared-memory buffer. There is one of these objects for each shared142** memory region opened by clients. If two clients open the same file,143** there are two TestvfsFile structures but only one TestvfsBuffer structure.144*/145struct TestvfsBuffer {146  char *zFile;                    /* Associated file name */147  int pgsz;                       /* Page size */148  u8 *aPage[TESTVFS_MAX_PAGES];   /* Array of ckalloc'd pages */149  TestvfsFd *pFile;               /* List of open handles */150  TestvfsBuffer *pNext;           /* Next in linked list of all buffers */151};152 153 154#define PARENTVFS(x) (((Testvfs *)((x)->pAppData))->pParent)155 156#define TESTVFS_MAX_ARGS 12157 158 159/*160** Method declarations for TestvfsFile.161*/162static int tvfsClose(sqlite3_file*);163static int tvfsRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);164static int tvfsWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);165static int tvfsTruncate(sqlite3_file*, sqlite3_int64 size);166static int tvfsSync(sqlite3_file*, int flags);167static int tvfsFileSize(sqlite3_file*, sqlite3_int64 *pSize);168static int tvfsLock(sqlite3_file*, int);169static int tvfsUnlock(sqlite3_file*, int);170static int tvfsCheckReservedLock(sqlite3_file*, int *);171static int tvfsFileControl(sqlite3_file*, int op, void *pArg);172static int tvfsSectorSize(sqlite3_file*);173static int tvfsDeviceCharacteristics(sqlite3_file*);174 175/*176** Method declarations for tvfs_vfs.177*/178static int tvfsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);179static int tvfsDelete(sqlite3_vfs*, const char *zName, int syncDir);180static int tvfsAccess(sqlite3_vfs*, const char *zName, int flags, int *);181static int tvfsFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);182#ifndef SQLITE_OMIT_LOAD_EXTENSION183static void *tvfsDlOpen(sqlite3_vfs*, const char *zFilename);184static void tvfsDlError(sqlite3_vfs*, int nByte, char *zErrMsg);185static void (*tvfsDlSym(sqlite3_vfs*,void*, const char *zSymbol))(void);186static void tvfsDlClose(sqlite3_vfs*, void*);187#endif /* SQLITE_OMIT_LOAD_EXTENSION */188static int tvfsRandomness(sqlite3_vfs*, int nByte, char *zOut);189static int tvfsSleep(sqlite3_vfs*, int microseconds);190static int tvfsCurrentTime(sqlite3_vfs*, double*);191 192static int tvfsShmOpen(sqlite3_file*);193static int tvfsShmLock(sqlite3_file*, int , int, int);194static int tvfsShmMap(sqlite3_file*,int,int,int, void volatile **);195static void tvfsShmBarrier(sqlite3_file*);196static int tvfsShmUnmap(sqlite3_file*, int);197 198static int tvfsFetch(sqlite3_file*, sqlite3_int64, int, void**);199static int tvfsUnfetch(sqlite3_file*, sqlite3_int64, void*);200 201static sqlite3_io_methods tvfs_io_methods = {202  3,                              /* iVersion */203  tvfsClose,                      /* xClose */204  tvfsRead,                       /* xRead */205  tvfsWrite,                      /* xWrite */206  tvfsTruncate,                   /* xTruncate */207  tvfsSync,                       /* xSync */208  tvfsFileSize,                   /* xFileSize */209  tvfsLock,                       /* xLock */210  tvfsUnlock,                     /* xUnlock */211  tvfsCheckReservedLock,          /* xCheckReservedLock */212  tvfsFileControl,                /* xFileControl */213  tvfsSectorSize,                 /* xSectorSize */214  tvfsDeviceCharacteristics,      /* xDeviceCharacteristics */215  tvfsShmMap,                     /* xShmMap */216  tvfsShmLock,                    /* xShmLock */217  tvfsShmBarrier,                 /* xShmBarrier */218  tvfsShmUnmap,                   /* xShmUnmap */219  tvfsFetch,220  tvfsUnfetch221};222 223static int tvfsResultCode(Testvfs *p, int *pRc){224  struct errcode {225    int eCode;226    const char *zCode;227  } aCode[] = {228    { SQLITE_OK,       "SQLITE_OK"     },229    { SQLITE_ERROR,    "SQLITE_ERROR"  },230    { SQLITE_IOERR,    "SQLITE_IOERR"  },231    { SQLITE_LOCKED,   "SQLITE_LOCKED" },232    { SQLITE_BUSY,     "SQLITE_BUSY"   },233    { SQLITE_READONLY, "SQLITE_READONLY"   },234    { SQLITE_READONLY_CANTINIT, "SQLITE_READONLY_CANTINIT"   },235    { SQLITE_NOTFOUND, "SQLITE_NOTFOUND"   },236    { -1,              "SQLITE_OMIT"   },237  };238 239  const char *z;240  int i;241 242  z = Tcl_GetStringResult(p->interp);243  for(i=0; i<ArraySize(aCode); i++){244    if( 0==strcmp(z, aCode[i].zCode) ){245      *pRc = aCode[i].eCode;246      return 1;247    }248  }249 250  return 0;251}252 253static int tvfsInjectFault(TestFaultInject *p){254  int ret = 0;255  if( p->eFault ){256    p->iCnt--;257    if( p->iCnt==0 || (p->iCnt<0 && p->eFault==FAULT_INJECT_PERSISTENT ) ){258      ret = 1;259      p->nFail++;260    }261  }262  return ret;263}264 265 266static int tvfsInjectIoerr(Testvfs *p){267  return tvfsInjectFault(&p->ioerr_err);268}269 270static int tvfsInjectFullerr(Testvfs *p){271  return tvfsInjectFault(&p->full_err);272}273static int tvfsInjectCantopenerr(Testvfs *p){274  return tvfsInjectFault(&p->cantopen_err);275}276 277 278static void tvfsExecTcl(279  Testvfs *p, 280  const char *zMethod,281  Tcl_Obj *arg1,282  Tcl_Obj *arg2,283  Tcl_Obj *arg3,284  Tcl_Obj *arg4285){286  int rc;                         /* Return code from Tcl_EvalObj() */287  Tcl_Obj *pEval;288  assert( p->pScript );289 290  assert( zMethod );291  assert( p );292  assert( arg2==0 || arg1!=0 );293  assert( arg3==0 || arg2!=0 );294 295  pEval = Tcl_DuplicateObj(p->pScript);296  Tcl_IncrRefCount(p->pScript);297  Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj(zMethod, -1));298  if( arg1 ) Tcl_ListObjAppendElement(p->interp, pEval, arg1);299  if( arg2 ) Tcl_ListObjAppendElement(p->interp, pEval, arg2);300  if( arg3 ) Tcl_ListObjAppendElement(p->interp, pEval, arg3);301  if( arg4 ) Tcl_ListObjAppendElement(p->interp, pEval, arg4);302 303  rc = Tcl_EvalObjEx(p->interp, pEval, TCL_EVAL_GLOBAL);304  if( rc!=TCL_OK ){305    Tcl_BackgroundError(p->interp);306    Tcl_ResetResult(p->interp);307  }308}309 310 311/*312** Close an tvfs-file.313*/314static int tvfsClose(sqlite3_file *pFile){315  TestvfsFile *pTestfile = (TestvfsFile *)pFile;316  TestvfsFd *pFd = pTestfile->pFd;317  Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;318 319  if( p->pScript && p->mask&TESTVFS_CLOSE_MASK ){320    tvfsExecTcl(p, "xClose", 321        Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0, 0322    );323  }324 325  if( pFd->pShmId ){326    Tcl_DecrRefCount(pFd->pShmId);327    pFd->pShmId = 0;328  }329  if( pFile->pMethods ){330    ckfree((char *)pFile->pMethods);331  }332  sqlite3OsClose(pFd->pReal);333  ckfree((char *)pFd);334  pTestfile->pFd = 0;335  return SQLITE_OK;336}337 338/*339** Read data from an tvfs-file.340*/341static int tvfsRead(342  sqlite3_file *pFile, 343  void *zBuf, 344  int iAmt, 345  sqlite_int64 iOfst346){347  int rc = SQLITE_OK;348  TestvfsFd *pFd = tvfsGetFd(pFile);349  Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;350  if( p->pScript && p->mask&TESTVFS_READ_MASK ){351    tvfsExecTcl(p, "xRead", 352        Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0, 0353    );354    tvfsResultCode(p, &rc);355  }356  if( rc==SQLITE_OK && p->mask&TESTVFS_READ_MASK && tvfsInjectIoerr(p) ){357    rc = SQLITE_IOERR;358  }359  if( rc==SQLITE_OK ){360    rc = sqlite3OsRead(pFd->pReal, zBuf, iAmt, iOfst);361  }362  return rc;363}364 365/*366** Write data to an tvfs-file.367*/368static int tvfsWrite(369  sqlite3_file *pFile, 370  const void *zBuf, 371  int iAmt, 372  sqlite_int64 iOfst373){374  int rc = SQLITE_OK;375  TestvfsFd *pFd = tvfsGetFd(pFile);376  Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;377 378  if( p->pScript && p->mask&TESTVFS_WRITE_MASK ){379    tvfsExecTcl(p, "xWrite", 380        Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 381        Tcl_NewWideIntObj(iOfst), Tcl_NewIntObj(iAmt)382    );383    tvfsResultCode(p, &rc);384    if( rc<0 ) return SQLITE_OK;385  }386 387  if( rc==SQLITE_OK && tvfsInjectFullerr(p) ){388    rc = SQLITE_FULL;389  }390  if( rc==SQLITE_OK && p->mask&TESTVFS_WRITE_MASK && tvfsInjectIoerr(p) ){391    rc = SQLITE_IOERR;392  }393  394  if( rc==SQLITE_OK ){395    rc = sqlite3OsWrite(pFd->pReal, zBuf, iAmt, iOfst);396  }397  return rc;398}399 400/*401** Truncate an tvfs-file.402*/403static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){404  int rc = SQLITE_OK;405  TestvfsFd *pFd = tvfsGetFd(pFile);406  Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;407 408  if( p->pScript && p->mask&TESTVFS_TRUNCATE_MASK ){409    tvfsExecTcl(p, "xTruncate", 410        Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0, 0411    );412    tvfsResultCode(p, &rc);413  }414  415  if( rc==SQLITE_OK ){416    rc = sqlite3OsTruncate(pFd->pReal, size);417  }418  return rc;419}420 421/*422** Sync an tvfs-file.423*/424static int tvfsSync(sqlite3_file *pFile, int flags){425  int rc = SQLITE_OK;426  TestvfsFd *pFd = tvfsGetFd(pFile);427  Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;428 429  if( p->pScript && p->mask&TESTVFS_SYNC_MASK ){430    char *zFlags = 0;431 432    switch( flags ){433      case SQLITE_SYNC_NORMAL:434        zFlags = "normal";435        break;436      case SQLITE_SYNC_FULL:437        zFlags = "full";438        break;439      case SQLITE_SYNC_NORMAL|SQLITE_SYNC_DATAONLY:440        zFlags = "normal|dataonly";441        break;442      case SQLITE_SYNC_FULL|SQLITE_SYNC_DATAONLY:443        zFlags = "full|dataonly";444        break;445      default:446        assert(0);447    }448 449    tvfsExecTcl(p, "xSync", 450        Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId,451        Tcl_NewStringObj(zFlags, -1), 0452    );453    tvfsResultCode(p, &rc);454  }455 456  if( rc==SQLITE_OK && tvfsInjectFullerr(p) ) rc = SQLITE_FULL;457 458  if( rc==SQLITE_OK ){459    rc = sqlite3OsSync(pFd->pReal, flags);460  }461 462  return rc;463}464 465/*466** Return the current file-size of an tvfs-file.467*/468static int tvfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){469  TestvfsFd *p = tvfsGetFd(pFile);470  return sqlite3OsFileSize(p->pReal, pSize);471}472 473/*474** Lock an tvfs-file.475*/476static int tvfsLock(sqlite3_file *pFile, int eLock){477  TestvfsFd *pFd = tvfsGetFd(pFile);478  Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;479  if( p->pScript && p->mask&TESTVFS_LOCK_MASK ){480    char zLock[30];481    sqlite3_snprintf(sizeof(zLock),zLock,"%d",eLock);482    tvfsExecTcl(p, "xLock", Tcl_NewStringObj(pFd->zFilename, -1), 483                   Tcl_NewStringObj(zLock, -1), 0, 0);484  }485  if( p->mask&TESTVFS_LOCK_MASK && tvfsInjectIoerr(p) ){486    return SQLITE_IOERR_LOCK;487  }488  return sqlite3OsLock(pFd->pReal, eLock);489}490 491/*492** Unlock an tvfs-file.493*/494static int tvfsUnlock(sqlite3_file *pFile, int eLock){495  TestvfsFd *pFd = tvfsGetFd(pFile);496  Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;497  if( p->pScript && p->mask&TESTVFS_UNLOCK_MASK ){498    char zLock[30];499    sqlite3_snprintf(sizeof(zLock),zLock,"%d",eLock);500    tvfsExecTcl(p, "xUnlock", Tcl_NewStringObj(pFd->zFilename, -1), 501                   Tcl_NewStringObj(zLock, -1), 0, 0);502  }503  if( p->mask&TESTVFS_UNLOCK_MASK && tvfsInjectIoerr(p) ){504    return SQLITE_IOERR_UNLOCK;505  }506  return sqlite3OsUnlock(pFd->pReal, eLock);507}508 509/*510** Check if another file-handle holds a RESERVED lock on an tvfs-file.511*/512static int tvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){513  TestvfsFd *pFd = tvfsGetFd(pFile);514  Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;515  if( p->pScript && p->mask&TESTVFS_CKLOCK_MASK ){516    tvfsExecTcl(p, "xCheckReservedLock", Tcl_NewStringObj(pFd->zFilename, -1),517                   0, 0, 0);518  }519  return sqlite3OsCheckReservedLock(pFd->pReal, pResOut);520}521 522/*523** File control method. For custom operations on an tvfs-file.524*/525static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){526  TestvfsFd *pFd = tvfsGetFd(pFile);527  Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;528  if( op==SQLITE_FCNTL_PRAGMA ){529    char **argv = (char**)pArg;530    if( sqlite3_stricmp(argv[1],"error")==0 ){531      int rc = SQLITE_ERROR;532      if( argv[2] ){533        const char *z = argv[2];534        int x = atoi(z);535        if( x ){536          rc = x;537          while( sqlite3Isdigit(z[0]) ){ z++; }538          while( sqlite3Isspace(z[0]) ){ z++; }539        }540        if( z[0] ) argv[0] = sqlite3_mprintf("%s", z);541      }542      return rc;543    }544    if( sqlite3_stricmp(argv[1], "filename")==0 ){545      argv[0] = sqlite3_mprintf("%s", pFd->zFilename);546      return SQLITE_OK;547    }548  }549  if( p->pScript && (p->mask&TESTVFS_FCNTL_MASK) ){550    struct Fcntl {551      int iFnctl;552      const char *zFnctl;553    } aF[] = {554      { SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, "BEGIN_ATOMIC_WRITE" },555      { SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, "COMMIT_ATOMIC_WRITE" },556      { SQLITE_FCNTL_ZIPVFS, "ZIPVFS" },557    };558    int i;559    for(i=0; i<sizeof(aF)/sizeof(aF[0]); i++){560      if( op==aF[i].iFnctl ) break;561    }562    if( i<sizeof(aF)/sizeof(aF[0]) ){563      int rc = 0;564      tvfsExecTcl(p, "xFileControl", 565          Tcl_NewStringObj(pFd->zFilename, -1), 566          Tcl_NewStringObj(aF[i].zFnctl, -1),567          0, 0568      );569      tvfsResultCode(p, &rc);570      if( rc ) return (rc<0 ? SQLITE_OK : rc);571    }572  }573  return sqlite3OsFileControl(pFd->pReal, op, pArg);574}575 576/*577** Return the sector-size in bytes for an tvfs-file.578*/579static int tvfsSectorSize(sqlite3_file *pFile){580  TestvfsFd *pFd = tvfsGetFd(pFile);581  Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;582  if( p->iSectorsize>=0 ){583    return p->iSectorsize;584  }585  return sqlite3OsSectorSize(pFd->pReal);586}587 588/*589** Return the device characteristic flags supported by an tvfs-file.590*/591static int tvfsDeviceCharacteristics(sqlite3_file *pFile){592  TestvfsFd *pFd = tvfsGetFd(pFile);593  Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;594  if( p->iDevchar>=0 ){595    return p->iDevchar;596  }597  return sqlite3OsDeviceCharacteristics(pFd->pReal);598}599 600/*601** Open an tvfs file handle.602*/603static int tvfsOpen(604  sqlite3_vfs *pVfs,605  const char *zName,606  sqlite3_file *pFile,607  int flags,608  int *pOutFlags609){610  int rc;611  TestvfsFile *pTestfile = (TestvfsFile *)pFile;612  TestvfsFd *pFd;613  Tcl_Obj *pId = 0;614  Testvfs *p = (Testvfs *)pVfs->pAppData;615 616  pFd = (TestvfsFd *)ckalloc(sizeof(TestvfsFd) + PARENTVFS(pVfs)->szOsFile);617  memset(pFd, 0, sizeof(TestvfsFd) + PARENTVFS(pVfs)->szOsFile);618  pFd->pShm = 0;619  pFd->pShmId = 0;620  pFd->zFilename = zName;621  pFd->pVfs = pVfs;622  pFd->pReal = (sqlite3_file *)&pFd[1];623  memset(pTestfile, 0, sizeof(TestvfsFile));624  pTestfile->pFd = pFd;625 626  /* Evaluate the Tcl script: 627  **628  **   SCRIPT xOpen FILENAME KEY-VALUE-ARGS629  **630  ** If the script returns an SQLite error code other than SQLITE_OK, an631  ** error is returned to the caller. If it returns SQLITE_OK, the new632  ** connection is named "anon". Otherwise, the value returned by the633  ** script is used as the connection name.634  */635  Tcl_ResetResult(p->interp);636  if( p->pScript && p->mask&TESTVFS_OPEN_MASK ){637    Tcl_Obj *pArg = Tcl_NewObj();638    Tcl_IncrRefCount(pArg);639    if( flags&SQLITE_OPEN_MAIN_DB ){640      const char *z = &zName[strlen(zName)+1];641      while( *z ){642        Tcl_ListObjAppendElement(0, pArg, Tcl_NewStringObj(z, -1));643        z += strlen(z) + 1;644        Tcl_ListObjAppendElement(0, pArg, Tcl_NewStringObj(z, -1));645        z += strlen(z) + 1;646      }647    }648    tvfsExecTcl(p, "xOpen", Tcl_NewStringObj(pFd->zFilename, -1), pArg, 0, 0);649    Tcl_DecrRefCount(pArg);650    if( tvfsResultCode(p, &rc) ){651      if( rc!=SQLITE_OK ) return rc;652    }else{653      pId = Tcl_GetObjResult(p->interp);654    }655  }656 657  if( (p->mask&TESTVFS_OPEN_MASK) &&  tvfsInjectIoerr(p) ) return SQLITE_IOERR;658  if( tvfsInjectCantopenerr(p) ) return SQLITE_CANTOPEN;659  if( tvfsInjectFullerr(p) ) return SQLITE_FULL;660 661  if( !pId ){662    pId = Tcl_NewStringObj("anon", -1);663  }664  Tcl_IncrRefCount(pId);665  pFd->pShmId = pId;666  Tcl_ResetResult(p->interp);667 668  rc = sqlite3OsOpen(PARENTVFS(pVfs), zName, pFd->pReal, flags, pOutFlags);669  if( pFd->pReal->pMethods ){670    sqlite3_io_methods *pMethods;671    int nByte;672 673    if( pVfs->iVersion>1 ){674      nByte = sizeof(sqlite3_io_methods);675    }else{676      nByte = offsetof(sqlite3_io_methods, xShmMap);677    }678 679    pMethods = (sqlite3_io_methods *)ckalloc(nByte);680    memcpy(pMethods, &tvfs_io_methods, nByte);681    pMethods->iVersion = pFd->pReal->pMethods->iVersion;682    if( pMethods->iVersion>pVfs->iVersion ){683      pMethods->iVersion = pVfs->iVersion;684    }685    if( pVfs->iVersion>1 && ((Testvfs *)pVfs->pAppData)->isNoshm ){686      pMethods->xShmUnmap = 0;687      pMethods->xShmLock = 0;688      pMethods->xShmBarrier = 0;689      pMethods->xShmMap = 0;690    }691    pFile->pMethods = pMethods;692  }693 694  return rc;695}696 697/*698** Delete the file located at zPath. If the dirSync argument is true,699** ensure the file-system modifications are synced to disk before700** returning.701*/702static int tvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){703  int rc = SQLITE_OK;704  Testvfs *p = (Testvfs *)pVfs->pAppData;705 706  if( p->pScript && p->mask&TESTVFS_DELETE_MASK ){707    tvfsExecTcl(p, "xDelete", 708        Tcl_NewStringObj(zPath, -1), Tcl_NewIntObj(dirSync), 0, 0709    );710    tvfsResultCode(p, &rc);711  }712  if( rc==SQLITE_OK ){713    rc = sqlite3OsDelete(PARENTVFS(pVfs), zPath, dirSync);714  }715  return rc;716}717 718/*719** Test for access permissions. Return true if the requested permission720** is available, or false otherwise.721*/722static int tvfsAccess(723  sqlite3_vfs *pVfs, 724  const char *zPath, 725  int flags, 726  int *pResOut727){728  Testvfs *p = (Testvfs *)pVfs->pAppData;729  if( p->pScript && p->mask&TESTVFS_ACCESS_MASK ){730    int rc;731    char *zArg = 0;732    if( flags==SQLITE_ACCESS_EXISTS ) zArg = "SQLITE_ACCESS_EXISTS";733    if( flags==SQLITE_ACCESS_READWRITE ) zArg = "SQLITE_ACCESS_READWRITE";734    if( flags==SQLITE_ACCESS_READ ) zArg = "SQLITE_ACCESS_READ";735    tvfsExecTcl(p, "xAccess", 736        Tcl_NewStringObj(zPath, -1), Tcl_NewStringObj(zArg, -1), 0, 0737    );738    if( tvfsResultCode(p, &rc) ){739      if( rc!=SQLITE_OK ) return rc;740    }else{741      Tcl_Interp *interp = p->interp;742      if( TCL_OK==Tcl_GetBooleanFromObj(0, Tcl_GetObjResult(interp), pResOut) ){743        return SQLITE_OK;744      }745    }746  }747  return sqlite3OsAccess(PARENTVFS(pVfs), zPath, flags, pResOut);748}749 750/*751** Populate buffer zOut with the full canonical pathname corresponding752** to the pathname in zPath. zOut is guaranteed to point to a buffer753** of at least (DEVSYM_MAX_PATHNAME+1) bytes.754*/755static int tvfsFullPathname(756  sqlite3_vfs *pVfs, 757  const char *zPath, 758  int nOut, 759  char *zOut760){761  Testvfs *p = (Testvfs *)pVfs->pAppData;762  if( p->pScript && p->mask&TESTVFS_FULLPATHNAME_MASK ){763    int rc;764    tvfsExecTcl(p, "xFullPathname", Tcl_NewStringObj(zPath, -1), 0, 0, 0);765    if( tvfsResultCode(p, &rc) ){766      if( rc!=SQLITE_OK ) return rc;767    }768  }769  return sqlite3OsFullPathname(PARENTVFS(pVfs), zPath, nOut, zOut);770}771 772#ifndef SQLITE_OMIT_LOAD_EXTENSION773/*774** Open the dynamic library located at zPath and return a handle.775*/776static void *tvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){777  return sqlite3OsDlOpen(PARENTVFS(pVfs), zPath);778}779 780/*781** Populate the buffer zErrMsg (size nByte bytes) with a human readable782** utf-8 string describing the most recent error encountered associated 783** with dynamic libraries.784*/785static void tvfsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){786  sqlite3OsDlError(PARENTVFS(pVfs), nByte, zErrMsg);787}788 789/*790** Return a pointer to the symbol zSymbol in the dynamic library pHandle.791*/792static void (*tvfsDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){793  return sqlite3OsDlSym(PARENTVFS(pVfs), p, zSym);794}795 796/*797** Close the dynamic library handle pHandle.798*/799static void tvfsDlClose(sqlite3_vfs *pVfs, void *pHandle){800  sqlite3OsDlClose(PARENTVFS(pVfs), pHandle);801}802#endif /* SQLITE_OMIT_LOAD_EXTENSION */803 804/*805** Populate the buffer pointed to by zBufOut with nByte bytes of 806** random data.807*/808static int tvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){809  return sqlite3OsRandomness(PARENTVFS(pVfs), nByte, zBufOut);810}811 812/*813** Sleep for nMicro microseconds. Return the number of microseconds 814** actually slept.815*/816static int tvfsSleep(sqlite3_vfs *pVfs, int nMicro){817  Testvfs *p = (Testvfs *)pVfs->pAppData;818  if( p->pScript && (p->mask&TESTVFS_SLEEP_MASK) ){819    tvfsExecTcl(p, "xSleep", Tcl_NewIntObj(nMicro), 0, 0, 0);820  }821  return sqlite3OsSleep(PARENTVFS(pVfs), nMicro);822}823 824/*825** Return the current time as a Julian Day number in *pTimeOut.826*/827static int tvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){828  return PARENTVFS(pVfs)->xCurrentTime(PARENTVFS(pVfs), pTimeOut);829}830 831static int tvfsShmOpen(sqlite3_file *pFile){832  Testvfs *p;833  int rc = SQLITE_OK;             /* Return code */834  TestvfsBuffer *pBuffer;         /* Buffer to open connection to */835  TestvfsFd *pFd;                 /* The testvfs file structure */836 837  pFd = tvfsGetFd(pFile);838  p = (Testvfs *)pFd->pVfs->pAppData;839  assert( 0==p->isFullshm );840  assert( pFd->pShmId && pFd->pShm==0 && pFd->pNext==0 );841 842  /* Evaluate the Tcl script: 843  **844  **   SCRIPT xShmOpen FILENAME845  */846  Tcl_ResetResult(p->interp);847  if( p->pScript && p->mask&TESTVFS_SHMOPEN_MASK ){848    tvfsExecTcl(p, "xShmOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0, 0);849    if( tvfsResultCode(p, &rc) ){850      if( rc!=SQLITE_OK ) return rc;851    }852  }853 854  assert( rc==SQLITE_OK );855  if( p->mask&TESTVFS_SHMOPEN_MASK && tvfsInjectIoerr(p) ){856    return SQLITE_IOERR;857  }858 859  /* Search for a TestvfsBuffer. Create a new one if required. */860  for(pBuffer=p->pBuffer; pBuffer; pBuffer=pBuffer->pNext){861    if( 0==strcmp(pFd->zFilename, pBuffer->zFile) ) break;862  }863  if( !pBuffer ){864    int szName = (int)strlen(pFd->zFilename);865    int nByte = sizeof(TestvfsBuffer) + szName + 1;866    pBuffer = (TestvfsBuffer *)ckalloc(nByte);867    memset(pBuffer, 0, nByte);868    pBuffer->zFile = (char *)&pBuffer[1];869    memcpy(pBuffer->zFile, pFd->zFilename, szName+1);870    pBuffer->pNext = p->pBuffer;871    p->pBuffer = pBuffer;872  }873 874  /* Connect the TestvfsBuffer to the new TestvfsShm handle and return. */875  pFd->pNext = pBuffer->pFile;876  pBuffer->pFile = pFd;877  pFd->pShm = pBuffer;878  return rc;879}880 881static void tvfsAllocPage(TestvfsBuffer *p, int iPage, int pgsz){882  assert( iPage<TESTVFS_MAX_PAGES );883  if( p->aPage[iPage]==0 ){884    p->aPage[iPage] = (u8 *)ckalloc(pgsz);885    memset(p->aPage[iPage], 0, pgsz);886    p->pgsz = pgsz;887  }888}889 890static int tvfsShmMap(891  sqlite3_file *pFile,            /* Handle open on database file */892  int iPage,                      /* Page to retrieve */893  int pgsz,                       /* Size of pages */894  int isWrite,                    /* True to extend file if necessary */895  void volatile **pp              /* OUT: Mapped memory */896){897  int rc = SQLITE_OK;898  TestvfsFd *pFd = tvfsGetFd(pFile);899  Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);900 901  if( p->isFullshm ){902    sqlite3_file *pReal = pFd->pReal;903    return pReal->pMethods->xShmMap(pReal, iPage, pgsz, isWrite, pp);904  }905 906  if( 0==pFd->pShm ){907    rc = tvfsShmOpen(pFile);908    if( rc!=SQLITE_OK ){909      return rc;910    }911  }912 913  if( p->pScript && p->mask&TESTVFS_SHMMAP_MASK ){914    Tcl_Obj *pArg = Tcl_NewObj();915    Tcl_IncrRefCount(pArg);916    Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(iPage));917    Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(pgsz));918    Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(isWrite));919    tvfsExecTcl(p, "xShmMap", 920        Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, pArg, 0921    );922    tvfsResultCode(p, &rc);923    Tcl_DecrRefCount(pArg);924  }925  if( rc==SQLITE_OK && p->mask&TESTVFS_SHMMAP_MASK && tvfsInjectIoerr(p) ){926    rc = SQLITE_IOERR;927  }928 929  if( rc==SQLITE_OK && isWrite && !pFd->pShm->aPage[iPage] ){930    tvfsAllocPage(pFd->pShm, iPage, pgsz);931  }932  if( rc==SQLITE_OK || rc==SQLITE_READONLY ){933    *pp = (void volatile *)pFd->pShm->aPage[iPage];934  }935 936  return rc;937}938 939 940static int tvfsShmLock(941  sqlite3_file *pFile,942  int ofst,943  int n,944  int flags945){946  int rc = SQLITE_OK;947  TestvfsFd *pFd = tvfsGetFd(pFile);948  Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);949  int nLock;950  char zLock[80];951 952  if( p->isFullshm ){953    sqlite3_file *pReal = pFd->pReal;954    return pReal->pMethods->xShmLock(pReal, ofst, n, flags);955  }956 957  if( p->pScript && p->mask&TESTVFS_SHMLOCK_MASK ){958    sqlite3_snprintf(sizeof(zLock), zLock, "%d %d", ofst, n);959    nLock = (int)strlen(zLock);960    if( flags & SQLITE_SHM_LOCK ){961      strcpy(&zLock[nLock], " lock");962    }else{963      strcpy(&zLock[nLock], " unlock");964    }965    nLock += (int)strlen(&zLock[nLock]);966    if( flags & SQLITE_SHM_SHARED ){967      strcpy(&zLock[nLock], " shared");968    }else{969      strcpy(&zLock[nLock], " exclusive");970    }971    tvfsExecTcl(p, "xShmLock", 972        Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId,973        Tcl_NewStringObj(zLock, -1), 0974    );975    tvfsResultCode(p, &rc);976  }977 978  if( rc==SQLITE_OK && p->mask&TESTVFS_SHMLOCK_MASK && tvfsInjectIoerr(p) ){979    rc = SQLITE_IOERR;980  }981 982  if( rc==SQLITE_OK ){983    int isLock = (flags & SQLITE_SHM_LOCK);984    int isExcl = (flags & SQLITE_SHM_EXCLUSIVE);985    u32 mask = (((1<<n)-1) << ofst);986    if( isLock ){987      TestvfsFd *p2;988      for(p2=pFd->pShm->pFile; p2; p2=p2->pNext){989        if( p2==pFd ) continue;990        if( (p2->excllock&mask) || (isExcl && p2->sharedlock&mask) ){991          rc = SQLITE_BUSY;992          break;993        }994      }995      if( rc==SQLITE_OK ){996        if( isExcl )  pFd->excllock |= mask;997        if( !isExcl ) pFd->sharedlock |= mask;998      }999    }else{1000      if( isExcl )  pFd->excllock &= (~mask);1001      if( !isExcl ) pFd->sharedlock &= (~mask);1002    }1003  }1004 1005  return rc;1006}1007 1008static void tvfsShmBarrier(sqlite3_file *pFile){1009  TestvfsFd *pFd = tvfsGetFd(pFile);1010  Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);1011 1012  if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){1013    const char *z = pFd->pShm ? pFd->pShm->zFile : "";1014    tvfsExecTcl(p, "xShmBarrier", Tcl_NewStringObj(z, -1), pFd->pShmId, 0, 0);1015  }1016 1017  if( p->isFullshm ){1018    sqlite3_file *pReal = pFd->pReal;1019    pReal->pMethods->xShmBarrier(pReal);1020    return;1021  }1022}1023 1024static int tvfsShmUnmap(1025  sqlite3_file *pFile,1026  int deleteFlag1027){1028  int rc = SQLITE_OK;1029  TestvfsFd *pFd = tvfsGetFd(pFile);1030  Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);1031  TestvfsBuffer *pBuffer = pFd->pShm;1032  TestvfsFd **ppFd;1033 1034  if( p->isFullshm ){1035    sqlite3_file *pReal = pFd->pReal;1036    return pReal->pMethods->xShmUnmap(pReal, deleteFlag);1037  }1038 1039  if( !pBuffer ) return SQLITE_OK;1040  assert( pFd->pShmId && pFd->pShm );1041 1042  if( p->pScript && p->mask&TESTVFS_SHMCLOSE_MASK ){1043    tvfsExecTcl(p, "xShmUnmap", 1044        Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0, 01045    );1046    tvfsResultCode(p, &rc);1047  }1048 1049  for(ppFd=&pBuffer->pFile; *ppFd!=pFd; ppFd=&((*ppFd)->pNext));1050  assert( (*ppFd)==pFd );1051  *ppFd = pFd->pNext;1052  pFd->pNext = 0;1053 1054  if( pBuffer->pFile==0 ){1055    int i;1056    TestvfsBuffer **pp;1057    for(pp=&p->pBuffer; *pp!=pBuffer; pp=&((*pp)->pNext));1058    *pp = (*pp)->pNext;1059    for(i=0; pBuffer->aPage[i]; i++){1060      ckfree((char *)pBuffer->aPage[i]);1061    }1062    ckfree((char *)pBuffer);1063  }1064  pFd->pShm = 0;1065 1066  return rc;1067}1068 1069static int tvfsFetch(1070    sqlite3_file *pFile, 1071    sqlite3_int64 iOfst, 1072    int iAmt, 1073    void **pp1074){1075  TestvfsFd *pFd = tvfsGetFd(pFile);1076  return sqlite3OsFetch(pFd->pReal, iOfst, iAmt, pp);1077}1078 1079static int tvfsUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *p){1080  TestvfsFd *pFd = tvfsGetFd(pFile);1081  return sqlite3OsUnfetch(pFd->pReal, iOfst, p);1082}1083 1084static int SQLITE_TCLAPI testvfs_obj_cmd(1085  ClientData cd,1086  Tcl_Interp *interp,1087  int objc,1088  Tcl_Obj *CONST objv[]1089){1090  Testvfs *p = (Testvfs *)cd;1091 1092  enum DB_enum { 1093    CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT, 1094    CMD_DEVCHAR, CMD_SECTORSIZE, CMD_FULLERR, CMD_CANTOPENERR1095  };1096  struct TestvfsSubcmd {1097    char *zName;1098    enum DB_enum eCmd;1099  } aSubcmd[] = {1100    { "shm",         CMD_SHM         },1101    { "delete",      CMD_DELETE      },1102    { "filter",      CMD_FILTER      },1103    { "ioerr",       CMD_IOERR       },1104    { "fullerr",     CMD_FULLERR     },1105    { "cantopenerr", CMD_CANTOPENERR },1106    { "script",      CMD_SCRIPT      },1107    { "devchar",     CMD_DEVCHAR     },1108    { "sectorsize",  CMD_SECTORSIZE  },1109    { 0, 0 }1110  };1111  int i;1112  1113  if( objc<2 ){1114    Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");1115    return TCL_ERROR;1116  }1117  if( Tcl_GetIndexFromObjStruct(1118        interp, objv[1], aSubcmd, sizeof(aSubcmd[0]), "subcommand", 0, &i) 1119  ){1120    return TCL_ERROR;1121  }1122  Tcl_ResetResult(interp);1123 1124  switch( aSubcmd[i].eCmd ){1125    case CMD_SHM: {1126      Tcl_Obj *pObj;1127      int rc;1128      TestvfsBuffer *pBuffer;1129      char *zName;1130      if( objc!=3 && objc!=4 ){1131        Tcl_WrongNumArgs(interp, 2, objv, "FILE ?VALUE?");1132        return TCL_ERROR;1133      }1134      zName = ckalloc(p->pParent->mxPathname);1135      rc = p->pParent->xFullPathname(1136          p->pParent, Tcl_GetString(objv[2]), 1137          p->pParent->mxPathname, zName1138      );1139      if( rc!=SQLITE_OK ){1140        Tcl_AppendResult(interp, "failed to get full path: ",1141                         Tcl_GetString(objv[2]), NULL);1142        ckfree(zName);1143        return TCL_ERROR;1144      }1145      for(pBuffer=p->pBuffer; pBuffer; pBuffer=pBuffer->pNext){1146        if( 0==strcmp(pBuffer->zFile, zName) ) break;1147      }1148      ckfree(zName);1149      if( !pBuffer ){1150        Tcl_AppendResult(interp, "no such file: ", Tcl_GetString(objv[2]), NULL);1151        return TCL_ERROR;1152      }1153      if( objc==4 ){1154        Tcl_Size n;1155        u8 *a = Tcl_GetByteArrayFromObj(objv[3], &n);1156        int pgsz = pBuffer->pgsz;1157        if( pgsz==0 ) pgsz = 65536;1158        for(i=0; i*pgsz<(int)n; i++){1159          int nByte = pgsz;1160          tvfsAllocPage(pBuffer, i, pgsz);1161          if( n-i*pgsz<pgsz ){1162            nByte = (int)n;1163          }1164          memcpy(pBuffer->aPage[i], &a[i*pgsz], nByte);1165        }1166      }1167 1168      pObj = Tcl_NewObj();1169      for(i=0; pBuffer->aPage[i]; i++){1170        int pgsz = pBuffer->pgsz;1171        if( pgsz==0 ) pgsz = 65536;1172        Tcl_AppendObjToObj(pObj, Tcl_NewByteArrayObj(pBuffer->aPage[i], pgsz));1173      }1174      Tcl_SetObjResult(interp, pObj);1175      break;1176    }1177 1178    /*  TESTVFS filter METHOD-LIST1179    **1180    **     Activate special processing for those methods contained in the list1181    */1182    case CMD_FILTER: {1183      static struct VfsMethod {1184        char *zName;1185        int mask;1186      } vfsmethod [] = {1187        { "xShmOpen",           TESTVFS_SHMOPEN_MASK },1188        { "xShmLock",           TESTVFS_SHMLOCK_MASK },1189        { "xShmBarrier",        TESTVFS_SHMBARRIER_MASK },1190        { "xShmUnmap",          TESTVFS_SHMCLOSE_MASK },1191        { "xShmMap",            TESTVFS_SHMMAP_MASK },1192        { "xSync",              TESTVFS_SYNC_MASK },1193        { "xDelete",            TESTVFS_DELETE_MASK },1194        { "xWrite",             TESTVFS_WRITE_MASK },1195        { "xRead",              TESTVFS_READ_MASK },1196        { "xTruncate",          TESTVFS_TRUNCATE_MASK },1197        { "xOpen",              TESTVFS_OPEN_MASK },1198        { "xClose",             TESTVFS_CLOSE_MASK },1199        { "xAccess",            TESTVFS_ACCESS_MASK },1200        { "xFullPathname",      TESTVFS_FULLPATHNAME_MASK },

Showing the first 1,200 of 1698 lines. Download the file for the rest.