/* ** File control method. For custom operations on an tvfs-file. */ static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){ TestvfsFd *p = tvfsGetFd(pFile); if( op==SQLITE_FCNTL_PRAGMA ){ char **argv = (char**)pArg; if( sqlite3_stricmp(argv[1],"error")==0 ){ int rc = SQLITE_ERROR; if( argv[2] ){ const char *z = argv[2]; int x = atoi(z); if( x ){ rc = x; while( sqlite3Isdigit(z[0]) ){ z++; } while( sqlite3Isspace(z[0]) ){ z++; } } if( z[0] ) argv[0] = sqlite3_mprintf("%s", z); } return rc; } if( sqlite3_stricmp(argv[1], "filename")==0 ){ argv[0] = sqlite3_mprintf("%s", p->zFilename); return SQLITE_OK; } } return sqlite3OsFileControl(p->pReal, op, pArg); }
/* ** Write data to an tvfs-file. */ static int tvfsWrite( sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite_int64 iOfst ){ int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_WRITE_MASK ){ tvfsExecTcl(p, "xWrite", Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, Tcl_NewWideIntObj(iOfst), Tcl_NewIntObj(iAmt) ); tvfsResultCode(p, &rc); } if( rc==SQLITE_OK && tvfsInjectFullerr(p) ){ rc = SQLITE_FULL; } if( rc==SQLITE_OK && p->mask&TESTVFS_WRITE_MASK && tvfsInjectIoerr(p) ){ rc = SQLITE_IOERR; } if( rc==SQLITE_OK ){ rc = sqlite3OsWrite(pFd->pReal, zBuf, iAmt, iOfst); } return rc; }
/* ** Unlock an tvfs-file. */ static int tvfsUnlock(sqlite3_file *pFile, int eLock){ TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->mask&TESTVFS_WRITE_MASK && tvfsInjectIoerr(p) ){ return SQLITE_IOERR_UNLOCK; } return sqlite3OsUnlock(pFd->pReal, eLock); }
/* ** Return the sector-size in bytes for an tvfs-file. */ static int tvfsSectorSize(sqlite3_file *pFile){ TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->iSectorsize>=0 ){ return p->iSectorsize; } return sqlite3OsSectorSize(pFd->pReal); }
/* ** Return the device characteristic flags supported by an tvfs-file. */ static int tvfsDeviceCharacteristics(sqlite3_file *pFile){ TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->iDevchar>=0 ){ return p->iDevchar; } return sqlite3OsDeviceCharacteristics(pFd->pReal); }
/* ** Check if another file-handle holds a RESERVED lock on an tvfs-file. */ static int tvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){ TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_CKLOCK_MASK ){ tvfsExecTcl(p, "xCheckReservedLock", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0, 0); } return sqlite3OsCheckReservedLock(pFd->pReal, pResOut); }
static int tvfsFetch( sqlite3_file *pFile, sqlite3_int64 iOfst, int iAmt, void **pp ){ TestvfsFd *pFd = tvfsGetFd(pFile); return sqlite3OsFetch(pFd->pReal, iOfst, iAmt, pp); }
/* ** Read data from an tvfs-file. */ static int tvfsRead( sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst ){ TestvfsFd *p = tvfsGetFd(pFile); return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst); }
static void tvfsShmBarrier(sqlite3_file *pFile){ TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){ tvfsExecTcl(p, "xShmBarrier", Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0 ); } }
/* ** Lock an tvfs-file. */ static int tvfsLock(sqlite3_file *pFile, int eLock){ TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_LOCK_MASK ){ char zLock[30]; sqlite3_snprintf(sizeof(zLock),zLock,"%d",eLock); tvfsExecTcl(p, "xLock", Tcl_NewStringObj(pFd->zFilename, -1), Tcl_NewStringObj(zLock, -1), 0, 0); } return sqlite3OsLock(pFd->pReal, eLock); }
/* ** Unlock an tvfs-file. */ static int tvfsUnlock(sqlite3_file *pFile, int eLock){ TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_UNLOCK_MASK ){ char zLock[30]; sqlite3_snprintf(sizeof(zLock),zLock,"%d",eLock); tvfsExecTcl(p, "xUnlock", Tcl_NewStringObj(pFd->zFilename, -1), Tcl_NewStringObj(zLock, -1), 0, 0); } if( p->mask&TESTVFS_WRITE_MASK && tvfsInjectIoerr(p) ){ return SQLITE_IOERR_UNLOCK; } return sqlite3OsUnlock(pFd->pReal, eLock); }
static int tvfsShmOpen(sqlite3_file *pFile){ Testvfs *p; int rc = SQLITE_OK; /* Return code */ TestvfsBuffer *pBuffer; /* Buffer to open connection to */ TestvfsFd *pFd; /* The testvfs file structure */ pFd = tvfsGetFd(pFile); p = (Testvfs *)pFd->pVfs->pAppData; assert( 0==p->isFullshm ); assert( pFd->pShmId && pFd->pShm==0 && pFd->pNext==0 ); /* Evaluate the Tcl script: ** ** SCRIPT xShmOpen FILENAME */ Tcl_ResetResult(p->interp); if( p->pScript && p->mask&TESTVFS_SHMOPEN_MASK ){ tvfsExecTcl(p, "xShmOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0, 0); if( tvfsResultCode(p, &rc) ){ if( rc!=SQLITE_OK ) return rc; } } assert( rc==SQLITE_OK ); if( p->mask&TESTVFS_SHMOPEN_MASK && tvfsInjectIoerr(p) ){ return SQLITE_IOERR; } /* Search for a TestvfsBuffer. Create a new one if required. */ for(pBuffer=p->pBuffer; pBuffer; pBuffer=pBuffer->pNext){ if( 0==strcmp(pFd->zFilename, pBuffer->zFile) ) break; } if( !pBuffer ){ int nByte = sizeof(TestvfsBuffer) + (int)strlen(pFd->zFilename) + 1; pBuffer = (TestvfsBuffer *)ckalloc(nByte); memset(pBuffer, 0, nByte); pBuffer->zFile = (char *)&pBuffer[1]; strcpy(pBuffer->zFile, pFd->zFilename); pBuffer->pNext = p->pBuffer; p->pBuffer = pBuffer; } /* Connect the TestvfsBuffer to the new TestvfsShm handle and return. */ pFd->pNext = pBuffer->pFile; pBuffer->pFile = pFd; pFd->pShm = pBuffer; return SQLITE_OK; }
/* ** Truncate an tvfs-file. */ static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){ int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_TRUNCATE_MASK ){ tvfsExecTcl(p, "xTruncate", Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0, 0 ); tvfsResultCode(p, &rc); } if( rc==SQLITE_OK ){ rc = sqlite3OsTruncate(pFd->pReal, size); } return rc; }
static int tvfsShmMap( sqlite3_file *pFile, /* Handle open on database file */ int iPage, /* Page to retrieve */ int pgsz, /* Size of pages */ int isWrite, /* True to extend file if necessary */ void volatile **pp /* OUT: Mapped memory */ ){ int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); if( p->isFullshm ){ return sqlite3OsShmMap(pFd->pReal, iPage, pgsz, isWrite, pp); } if( 0==pFd->pShm ){ rc = tvfsShmOpen(pFile); if( rc!=SQLITE_OK ){ return rc; } } if( p->pScript && p->mask&TESTVFS_SHMMAP_MASK ){ Tcl_Obj *pArg = Tcl_NewObj(); Tcl_IncrRefCount(pArg); Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(iPage)); Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(pgsz)); Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(isWrite)); tvfsExecTcl(p, "xShmMap", Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, pArg, 0 ); tvfsResultCode(p, &rc); Tcl_DecrRefCount(pArg); } if( rc==SQLITE_OK && p->mask&TESTVFS_SHMMAP_MASK && tvfsInjectIoerr(p) ){ rc = SQLITE_IOERR; } if( rc==SQLITE_OK && isWrite && !pFd->pShm->aPage[iPage] ){ tvfsAllocPage(pFd->pShm, iPage, pgsz); } *pp = (void volatile *)pFd->pShm->aPage[iPage]; return rc; }
static int tvfsShmUnmap( sqlite3_file *pFile, int deleteFlag ){ int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); TestvfsBuffer *pBuffer = pFd->pShm; TestvfsFd **ppFd; if( p->isFullshm ){ return sqlite3OsShmUnmap(pFd->pReal, deleteFlag); } if( !pBuffer ) return SQLITE_OK; assert( pFd->pShmId && pFd->pShm ); if( p->pScript && p->mask&TESTVFS_SHMCLOSE_MASK ){ tvfsExecTcl(p, "xShmUnmap", Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0, 0 ); tvfsResultCode(p, &rc); } for(ppFd=&pBuffer->pFile; *ppFd!=pFd; ppFd=&((*ppFd)->pNext)); assert( (*ppFd)==pFd ); *ppFd = pFd->pNext; pFd->pNext = 0; if( pBuffer->pFile==0 ){ int i; TestvfsBuffer **pp; for(pp=&p->pBuffer; *pp!=pBuffer; pp=&((*pp)->pNext)); *pp = (*pp)->pNext; for(i=0; pBuffer->aPage[i]; i++){ ckfree((char *)pBuffer->aPage[i]); } ckfree((char *)pBuffer); } pFd->pShm = 0; return rc; }
/* ** Sync an tvfs-file. */ static int tvfsSync(sqlite3_file *pFile, int flags){ int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_SYNC_MASK ){ char *zFlags; switch( flags ){ case SQLITE_SYNC_NORMAL: zFlags = "normal"; break; case SQLITE_SYNC_FULL: zFlags = "full"; break; case SQLITE_SYNC_NORMAL|SQLITE_SYNC_DATAONLY: zFlags = "normal|dataonly"; break; case SQLITE_SYNC_FULL|SQLITE_SYNC_DATAONLY: zFlags = "full|dataonly"; break; default: assert(0); } tvfsExecTcl(p, "xSync", Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, Tcl_NewStringObj(zFlags, -1), 0 ); tvfsResultCode(p, &rc); } if( rc==SQLITE_OK && tvfsInjectFullerr(p) ) rc = SQLITE_FULL; if( rc==SQLITE_OK ){ rc = sqlite3OsSync(pFd->pReal, flags); } return rc; }
/* ** Read data from an tvfs-file. */ static int tvfsRead( sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst ){ int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_READ_MASK ){ tvfsExecTcl(p, "xRead", Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0, 0 ); tvfsResultCode(p, &rc); } if( rc==SQLITE_OK && p->mask&TESTVFS_READ_MASK && tvfsInjectIoerr(p) ){ rc = SQLITE_IOERR; } if( rc==SQLITE_OK ){ rc = sqlite3OsRead(pFd->pReal, zBuf, iAmt, iOfst); } return rc; }
/* ** Return the current file-size of an tvfs-file. */ static int tvfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ TestvfsFd *p = tvfsGetFd(pFile); return sqlite3OsFileSize(p->pReal, pSize); }
static int tvfsShmLock( sqlite3_file *pFile, int ofst, int n, int flags ){ int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); int nLock; char zLock[80]; if( p->isFullshm ){ return sqlite3OsShmLock(pFd->pReal, ofst, n, flags); } if( p->pScript && p->mask&TESTVFS_SHMLOCK_MASK ){ sqlite3_snprintf(sizeof(zLock), zLock, "%d %d", ofst, n); nLock = (int)strlen(zLock); if( flags & SQLITE_SHM_LOCK ){ strcpy(&zLock[nLock], " lock"); }else{ strcpy(&zLock[nLock], " unlock"); } nLock += (int)strlen(&zLock[nLock]); if( flags & SQLITE_SHM_SHARED ){ strcpy(&zLock[nLock], " shared"); }else{ strcpy(&zLock[nLock], " exclusive"); } tvfsExecTcl(p, "xShmLock", Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, Tcl_NewStringObj(zLock, -1), 0 ); tvfsResultCode(p, &rc); } if( rc==SQLITE_OK && p->mask&TESTVFS_SHMLOCK_MASK && tvfsInjectIoerr(p) ){ rc = SQLITE_IOERR; } if( rc==SQLITE_OK ){ int isLock = (flags & SQLITE_SHM_LOCK); int isExcl = (flags & SQLITE_SHM_EXCLUSIVE); u32 mask = (((1<<n)-1) << ofst); if( isLock ){ TestvfsFd *p2; for(p2=pFd->pShm->pFile; p2; p2=p2->pNext){ if( p2==pFd ) continue; if( (p2->excllock&mask) || (isExcl && p2->sharedlock&mask) ){ rc = SQLITE_BUSY; break; } } if( rc==SQLITE_OK ){ if( isExcl ) pFd->excllock |= mask; if( !isExcl ) pFd->sharedlock |= mask; } }else{ if( isExcl ) pFd->excllock &= (~mask); if( !isExcl ) pFd->sharedlock &= (~mask); } } return rc; }
/* ** File control method. For custom operations on an tvfs-file. */ static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){ TestvfsFd *p = tvfsGetFd(pFile); return sqlite3OsFileControl(p->pReal, op, pArg); }
/* ** Lock an tvfs-file. */ static int tvfsLock(sqlite3_file *pFile, int eLock){ TestvfsFd *p = tvfsGetFd(pFile); return sqlite3OsLock(p->pReal, eLock); }
/* ** Check if another file-handle holds a RESERVED lock on an tvfs-file. */ static int tvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){ TestvfsFd *p = tvfsGetFd(pFile); return sqlite3OsCheckReservedLock(p->pReal, pResOut); }