test_vfs.c 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510
  1. /*
  2. ** 2010 May 05
  3. **
  4. ** The author disclaims copyright to this source code. In place of
  5. ** 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 and
  15. ** 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. #include "sqlite3.h"
  29. #include "sqliteInt.h"
  30. #include <tcl.h>
  31. typedef struct Testvfs Testvfs;
  32. typedef struct TestvfsShm TestvfsShm;
  33. typedef struct TestvfsBuffer TestvfsBuffer;
  34. typedef struct TestvfsFile TestvfsFile;
  35. typedef struct TestvfsFd TestvfsFd;
  36. /*
  37. ** An open file handle.
  38. */
  39. struct TestvfsFile {
  40. sqlite3_file base; /* Base class. Must be first */
  41. TestvfsFd *pFd; /* File data */
  42. };
  43. #define tvfsGetFd(pFile) (((TestvfsFile *)pFile)->pFd)
  44. struct TestvfsFd {
  45. sqlite3_vfs *pVfs; /* The VFS */
  46. const char *zFilename; /* Filename as passed to xOpen() */
  47. sqlite3_file *pReal; /* The real, underlying file descriptor */
  48. Tcl_Obj *pShmId; /* Shared memory id for Tcl callbacks */
  49. TestvfsBuffer *pShm; /* Shared memory buffer */
  50. u32 excllock; /* Mask of exclusive locks */
  51. u32 sharedlock; /* Mask of shared locks */
  52. TestvfsFd *pNext; /* Next handle opened on the same file */
  53. };
  54. #define FAULT_INJECT_NONE 0
  55. #define FAULT_INJECT_TRANSIENT 1
  56. #define FAULT_INJECT_PERSISTENT 2
  57. typedef struct TestFaultInject TestFaultInject;
  58. struct TestFaultInject {
  59. int iCnt; /* Remaining calls before fault injection */
  60. int eFault; /* A FAULT_INJECT_* value */
  61. int nFail; /* Number of faults injected */
  62. };
  63. /*
  64. ** An instance of this structure is allocated for each VFS created. The
  65. ** sqlite3_vfs.pAppData field of the VFS structure registered with SQLite
  66. ** is set to point to it.
  67. */
  68. struct Testvfs {
  69. char *zName; /* Name of this VFS */
  70. sqlite3_vfs *pParent; /* The VFS to use for file IO */
  71. sqlite3_vfs *pVfs; /* The testvfs registered with SQLite */
  72. Tcl_Interp *interp; /* Interpreter to run script in */
  73. Tcl_Obj *pScript; /* Script to execute */
  74. TestvfsBuffer *pBuffer; /* List of shared buffers */
  75. int isNoshm;
  76. int isFullshm;
  77. int mask; /* Mask controlling [script] and [ioerr] */
  78. TestFaultInject ioerr_err;
  79. TestFaultInject full_err;
  80. TestFaultInject cantopen_err;
  81. #if 0
  82. int iIoerrCnt;
  83. int ioerr;
  84. int nIoerrFail;
  85. int iFullCnt;
  86. int fullerr;
  87. int nFullFail;
  88. #endif
  89. int iDevchar;
  90. int iSectorsize;
  91. };
  92. /*
  93. ** The Testvfs.mask variable is set to a combination of the following.
  94. ** If a bit is clear in Testvfs.mask, then calls made by SQLite to the
  95. ** corresponding VFS method is ignored for purposes of:
  96. **
  97. ** + Simulating IO errors, and
  98. ** + Invoking the Tcl callback script.
  99. */
  100. #define TESTVFS_SHMOPEN_MASK 0x00000001
  101. #define TESTVFS_SHMLOCK_MASK 0x00000010
  102. #define TESTVFS_SHMMAP_MASK 0x00000020
  103. #define TESTVFS_SHMBARRIER_MASK 0x00000040
  104. #define TESTVFS_SHMCLOSE_MASK 0x00000080
  105. #define TESTVFS_OPEN_MASK 0x00000100
  106. #define TESTVFS_SYNC_MASK 0x00000200
  107. #define TESTVFS_DELETE_MASK 0x00000400
  108. #define TESTVFS_CLOSE_MASK 0x00000800
  109. #define TESTVFS_WRITE_MASK 0x00001000
  110. #define TESTVFS_TRUNCATE_MASK 0x00002000
  111. #define TESTVFS_ACCESS_MASK 0x00004000
  112. #define TESTVFS_FULLPATHNAME_MASK 0x00008000
  113. #define TESTVFS_READ_MASK 0x00010000
  114. #define TESTVFS_UNLOCK_MASK 0x00020000
  115. #define TESTVFS_ALL_MASK 0x0003FFFF
  116. #define TESTVFS_MAX_PAGES 1024
  117. /*
  118. ** A shared-memory buffer. There is one of these objects for each shared
  119. ** memory region opened by clients. If two clients open the same file,
  120. ** there are two TestvfsFile structures but only one TestvfsBuffer structure.
  121. */
  122. struct TestvfsBuffer {
  123. char *zFile; /* Associated file name */
  124. int pgsz; /* Page size */
  125. u8 *aPage[TESTVFS_MAX_PAGES]; /* Array of ckalloc'd pages */
  126. TestvfsFd *pFile; /* List of open handles */
  127. TestvfsBuffer *pNext; /* Next in linked list of all buffers */
  128. };
  129. #define PARENTVFS(x) (((Testvfs *)((x)->pAppData))->pParent)
  130. #define TESTVFS_MAX_ARGS 12
  131. /*
  132. ** Method declarations for TestvfsFile.
  133. */
  134. static int tvfsClose(sqlite3_file*);
  135. static int tvfsRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
  136. static int tvfsWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
  137. static int tvfsTruncate(sqlite3_file*, sqlite3_int64 size);
  138. static int tvfsSync(sqlite3_file*, int flags);
  139. static int tvfsFileSize(sqlite3_file*, sqlite3_int64 *pSize);
  140. static int tvfsLock(sqlite3_file*, int);
  141. static int tvfsUnlock(sqlite3_file*, int);
  142. static int tvfsCheckReservedLock(sqlite3_file*, int *);
  143. static int tvfsFileControl(sqlite3_file*, int op, void *pArg);
  144. static int tvfsSectorSize(sqlite3_file*);
  145. static int tvfsDeviceCharacteristics(sqlite3_file*);
  146. /*
  147. ** Method declarations for tvfs_vfs.
  148. */
  149. static int tvfsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
  150. static int tvfsDelete(sqlite3_vfs*, const char *zName, int syncDir);
  151. static int tvfsAccess(sqlite3_vfs*, const char *zName, int flags, int *);
  152. static int tvfsFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
  153. #ifndef SQLITE_OMIT_LOAD_EXTENSION
  154. static void *tvfsDlOpen(sqlite3_vfs*, const char *zFilename);
  155. static void tvfsDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
  156. static void (*tvfsDlSym(sqlite3_vfs*,void*, const char *zSymbol))(void);
  157. static void tvfsDlClose(sqlite3_vfs*, void*);
  158. #endif /* SQLITE_OMIT_LOAD_EXTENSION */
  159. static int tvfsRandomness(sqlite3_vfs*, int nByte, char *zOut);
  160. static int tvfsSleep(sqlite3_vfs*, int microseconds);
  161. static int tvfsCurrentTime(sqlite3_vfs*, double*);
  162. static int tvfsShmOpen(sqlite3_file*);
  163. static int tvfsShmLock(sqlite3_file*, int , int, int);
  164. static int tvfsShmMap(sqlite3_file*,int,int,int, void volatile **);
  165. static void tvfsShmBarrier(sqlite3_file*);
  166. static int tvfsShmUnmap(sqlite3_file*, int);
  167. static int tvfsFetch(sqlite3_file*, sqlite3_int64, int, void**);
  168. static int tvfsUnfetch(sqlite3_file*, sqlite3_int64, void*);
  169. static sqlite3_io_methods tvfs_io_methods = {
  170. 3, /* iVersion */
  171. tvfsClose, /* xClose */
  172. tvfsRead, /* xRead */
  173. tvfsWrite, /* xWrite */
  174. tvfsTruncate, /* xTruncate */
  175. tvfsSync, /* xSync */
  176. tvfsFileSize, /* xFileSize */
  177. tvfsLock, /* xLock */
  178. tvfsUnlock, /* xUnlock */
  179. tvfsCheckReservedLock, /* xCheckReservedLock */
  180. tvfsFileControl, /* xFileControl */
  181. tvfsSectorSize, /* xSectorSize */
  182. tvfsDeviceCharacteristics, /* xDeviceCharacteristics */
  183. tvfsShmMap, /* xShmMap */
  184. tvfsShmLock, /* xShmLock */
  185. tvfsShmBarrier, /* xShmBarrier */
  186. tvfsShmUnmap, /* xShmUnmap */
  187. tvfsFetch,
  188. tvfsUnfetch
  189. };
  190. static int tvfsResultCode(Testvfs *p, int *pRc){
  191. struct errcode {
  192. int eCode;
  193. const char *zCode;
  194. } aCode[] = {
  195. { SQLITE_OK, "SQLITE_OK" },
  196. { SQLITE_ERROR, "SQLITE_ERROR" },
  197. { SQLITE_IOERR, "SQLITE_IOERR" },
  198. { SQLITE_LOCKED, "SQLITE_LOCKED" },
  199. { SQLITE_BUSY, "SQLITE_BUSY" },
  200. };
  201. const char *z;
  202. int i;
  203. z = Tcl_GetStringResult(p->interp);
  204. for(i=0; i<ArraySize(aCode); i++){
  205. if( 0==strcmp(z, aCode[i].zCode) ){
  206. *pRc = aCode[i].eCode;
  207. return 1;
  208. }
  209. }
  210. return 0;
  211. }
  212. static int tvfsInjectFault(TestFaultInject *p){
  213. int ret = 0;
  214. if( p->eFault ){
  215. p->iCnt--;
  216. if( p->iCnt==0 || (p->iCnt<0 && p->eFault==FAULT_INJECT_PERSISTENT ) ){
  217. ret = 1;
  218. p->nFail++;
  219. }
  220. }
  221. return ret;
  222. }
  223. static int tvfsInjectIoerr(Testvfs *p){
  224. return tvfsInjectFault(&p->ioerr_err);
  225. }
  226. static int tvfsInjectFullerr(Testvfs *p){
  227. return tvfsInjectFault(&p->full_err);
  228. }
  229. static int tvfsInjectCantopenerr(Testvfs *p){
  230. return tvfsInjectFault(&p->cantopen_err);
  231. }
  232. static void tvfsExecTcl(
  233. Testvfs *p,
  234. const char *zMethod,
  235. Tcl_Obj *arg1,
  236. Tcl_Obj *arg2,
  237. Tcl_Obj *arg3,
  238. Tcl_Obj *arg4
  239. ){
  240. int rc; /* Return code from Tcl_EvalObj() */
  241. Tcl_Obj *pEval;
  242. assert( p->pScript );
  243. assert( zMethod );
  244. assert( p );
  245. assert( arg2==0 || arg1!=0 );
  246. assert( arg3==0 || arg2!=0 );
  247. pEval = Tcl_DuplicateObj(p->pScript);
  248. Tcl_IncrRefCount(p->pScript);
  249. Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj(zMethod, -1));
  250. if( arg1 ) Tcl_ListObjAppendElement(p->interp, pEval, arg1);
  251. if( arg2 ) Tcl_ListObjAppendElement(p->interp, pEval, arg2);
  252. if( arg3 ) Tcl_ListObjAppendElement(p->interp, pEval, arg3);
  253. if( arg4 ) Tcl_ListObjAppendElement(p->interp, pEval, arg4);
  254. rc = Tcl_EvalObjEx(p->interp, pEval, TCL_EVAL_GLOBAL);
  255. if( rc!=TCL_OK ){
  256. Tcl_BackgroundError(p->interp);
  257. Tcl_ResetResult(p->interp);
  258. }
  259. }
  260. /*
  261. ** Close an tvfs-file.
  262. */
  263. static int tvfsClose(sqlite3_file *pFile){
  264. int rc;
  265. TestvfsFile *pTestfile = (TestvfsFile *)pFile;
  266. TestvfsFd *pFd = pTestfile->pFd;
  267. Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
  268. if( p->pScript && p->mask&TESTVFS_CLOSE_MASK ){
  269. tvfsExecTcl(p, "xClose",
  270. Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0, 0
  271. );
  272. }
  273. if( pFd->pShmId ){
  274. Tcl_DecrRefCount(pFd->pShmId);
  275. pFd->pShmId = 0;
  276. }
  277. if( pFile->pMethods ){
  278. ckfree((char *)pFile->pMethods);
  279. }
  280. rc = sqlite3OsClose(pFd->pReal);
  281. ckfree((char *)pFd);
  282. pTestfile->pFd = 0;
  283. return rc;
  284. }
  285. /*
  286. ** Read data from an tvfs-file.
  287. */
  288. static int tvfsRead(
  289. sqlite3_file *pFile,
  290. void *zBuf,
  291. int iAmt,
  292. sqlite_int64 iOfst
  293. ){
  294. int rc = SQLITE_OK;
  295. TestvfsFd *pFd = tvfsGetFd(pFile);
  296. Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
  297. if( p->pScript && p->mask&TESTVFS_READ_MASK ){
  298. tvfsExecTcl(p, "xRead",
  299. Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0, 0
  300. );
  301. tvfsResultCode(p, &rc);
  302. }
  303. if( rc==SQLITE_OK && p->mask&TESTVFS_READ_MASK && tvfsInjectIoerr(p) ){
  304. rc = SQLITE_IOERR;
  305. }
  306. if( rc==SQLITE_OK ){
  307. rc = sqlite3OsRead(pFd->pReal, zBuf, iAmt, iOfst);
  308. }
  309. return rc;
  310. }
  311. /*
  312. ** Write data to an tvfs-file.
  313. */
  314. static int tvfsWrite(
  315. sqlite3_file *pFile,
  316. const void *zBuf,
  317. int iAmt,
  318. sqlite_int64 iOfst
  319. ){
  320. int rc = SQLITE_OK;
  321. TestvfsFd *pFd = tvfsGetFd(pFile);
  322. Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
  323. if( p->pScript && p->mask&TESTVFS_WRITE_MASK ){
  324. tvfsExecTcl(p, "xWrite",
  325. Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId,
  326. Tcl_NewWideIntObj(iOfst), Tcl_NewIntObj(iAmt)
  327. );
  328. tvfsResultCode(p, &rc);
  329. }
  330. if( rc==SQLITE_OK && tvfsInjectFullerr(p) ){
  331. rc = SQLITE_FULL;
  332. }
  333. if( rc==SQLITE_OK && p->mask&TESTVFS_WRITE_MASK && tvfsInjectIoerr(p) ){
  334. rc = SQLITE_IOERR;
  335. }
  336. if( rc==SQLITE_OK ){
  337. rc = sqlite3OsWrite(pFd->pReal, zBuf, iAmt, iOfst);
  338. }
  339. return rc;
  340. }
  341. /*
  342. ** Truncate an tvfs-file.
  343. */
  344. static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
  345. int rc = SQLITE_OK;
  346. TestvfsFd *pFd = tvfsGetFd(pFile);
  347. Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
  348. if( p->pScript && p->mask&TESTVFS_TRUNCATE_MASK ){
  349. tvfsExecTcl(p, "xTruncate",
  350. Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0, 0
  351. );
  352. tvfsResultCode(p, &rc);
  353. }
  354. if( rc==SQLITE_OK ){
  355. rc = sqlite3OsTruncate(pFd->pReal, size);
  356. }
  357. return rc;
  358. }
  359. /*
  360. ** Sync an tvfs-file.
  361. */
  362. static int tvfsSync(sqlite3_file *pFile, int flags){
  363. int rc = SQLITE_OK;
  364. TestvfsFd *pFd = tvfsGetFd(pFile);
  365. Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
  366. if( p->pScript && p->mask&TESTVFS_SYNC_MASK ){
  367. char *zFlags;
  368. switch( flags ){
  369. case SQLITE_SYNC_NORMAL:
  370. zFlags = "normal";
  371. break;
  372. case SQLITE_SYNC_FULL:
  373. zFlags = "full";
  374. break;
  375. case SQLITE_SYNC_NORMAL|SQLITE_SYNC_DATAONLY:
  376. zFlags = "normal|dataonly";
  377. break;
  378. case SQLITE_SYNC_FULL|SQLITE_SYNC_DATAONLY:
  379. zFlags = "full|dataonly";
  380. break;
  381. default:
  382. assert(0);
  383. }
  384. tvfsExecTcl(p, "xSync",
  385. Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId,
  386. Tcl_NewStringObj(zFlags, -1), 0
  387. );
  388. tvfsResultCode(p, &rc);
  389. }
  390. if( rc==SQLITE_OK && tvfsInjectFullerr(p) ) rc = SQLITE_FULL;
  391. if( rc==SQLITE_OK ){
  392. rc = sqlite3OsSync(pFd->pReal, flags);
  393. }
  394. return rc;
  395. }
  396. /*
  397. ** Return the current file-size of an tvfs-file.
  398. */
  399. static int tvfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
  400. TestvfsFd *p = tvfsGetFd(pFile);
  401. return sqlite3OsFileSize(p->pReal, pSize);
  402. }
  403. /*
  404. ** Lock an tvfs-file.
  405. */
  406. static int tvfsLock(sqlite3_file *pFile, int eLock){
  407. TestvfsFd *p = tvfsGetFd(pFile);
  408. return sqlite3OsLock(p->pReal, eLock);
  409. }
  410. /*
  411. ** Unlock an tvfs-file.
  412. */
  413. static int tvfsUnlock(sqlite3_file *pFile, int eLock){
  414. TestvfsFd *pFd = tvfsGetFd(pFile);
  415. Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
  416. if( p->mask&TESTVFS_WRITE_MASK && tvfsInjectIoerr(p) ){
  417. return SQLITE_IOERR_UNLOCK;
  418. }
  419. return sqlite3OsUnlock(pFd->pReal, eLock);
  420. }
  421. /*
  422. ** Check if another file-handle holds a RESERVED lock on an tvfs-file.
  423. */
  424. static int tvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
  425. TestvfsFd *p = tvfsGetFd(pFile);
  426. return sqlite3OsCheckReservedLock(p->pReal, pResOut);
  427. }
  428. /*
  429. ** File control method. For custom operations on an tvfs-file.
  430. */
  431. static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){
  432. TestvfsFd *p = tvfsGetFd(pFile);
  433. if( op==SQLITE_FCNTL_PRAGMA ){
  434. char **argv = (char**)pArg;
  435. if( sqlite3_stricmp(argv[1],"error")==0 ){
  436. int rc = SQLITE_ERROR;
  437. if( argv[2] ){
  438. const char *z = argv[2];
  439. int x = atoi(z);
  440. if( x ){
  441. rc = x;
  442. while( sqlite3Isdigit(z[0]) ){ z++; }
  443. while( sqlite3Isspace(z[0]) ){ z++; }
  444. }
  445. if( z[0] ) argv[0] = sqlite3_mprintf("%s", z);
  446. }
  447. return rc;
  448. }
  449. if( sqlite3_stricmp(argv[1], "filename")==0 ){
  450. argv[0] = sqlite3_mprintf("%s", p->zFilename);
  451. return SQLITE_OK;
  452. }
  453. }
  454. return sqlite3OsFileControl(p->pReal, op, pArg);
  455. }
  456. /*
  457. ** Return the sector-size in bytes for an tvfs-file.
  458. */
  459. static int tvfsSectorSize(sqlite3_file *pFile){
  460. TestvfsFd *pFd = tvfsGetFd(pFile);
  461. Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
  462. if( p->iSectorsize>=0 ){
  463. return p->iSectorsize;
  464. }
  465. return sqlite3OsSectorSize(pFd->pReal);
  466. }
  467. /*
  468. ** Return the device characteristic flags supported by an tvfs-file.
  469. */
  470. static int tvfsDeviceCharacteristics(sqlite3_file *pFile){
  471. TestvfsFd *pFd = tvfsGetFd(pFile);
  472. Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
  473. if( p->iDevchar>=0 ){
  474. return p->iDevchar;
  475. }
  476. return sqlite3OsDeviceCharacteristics(pFd->pReal);
  477. }
  478. /*
  479. ** Open an tvfs file handle.
  480. */
  481. static int tvfsOpen(
  482. sqlite3_vfs *pVfs,
  483. const char *zName,
  484. sqlite3_file *pFile,
  485. int flags,
  486. int *pOutFlags
  487. ){
  488. int rc;
  489. TestvfsFile *pTestfile = (TestvfsFile *)pFile;
  490. TestvfsFd *pFd;
  491. Tcl_Obj *pId = 0;
  492. Testvfs *p = (Testvfs *)pVfs->pAppData;
  493. pFd = (TestvfsFd *)ckalloc(sizeof(TestvfsFd) + PARENTVFS(pVfs)->szOsFile);
  494. memset(pFd, 0, sizeof(TestvfsFd) + PARENTVFS(pVfs)->szOsFile);
  495. pFd->pShm = 0;
  496. pFd->pShmId = 0;
  497. pFd->zFilename = zName;
  498. pFd->pVfs = pVfs;
  499. pFd->pReal = (sqlite3_file *)&pFd[1];
  500. memset(pTestfile, 0, sizeof(TestvfsFile));
  501. pTestfile->pFd = pFd;
  502. /* Evaluate the Tcl script:
  503. **
  504. ** SCRIPT xOpen FILENAME KEY-VALUE-ARGS
  505. **
  506. ** If the script returns an SQLite error code other than SQLITE_OK, an
  507. ** error is returned to the caller. If it returns SQLITE_OK, the new
  508. ** connection is named "anon". Otherwise, the value returned by the
  509. ** script is used as the connection name.
  510. */
  511. Tcl_ResetResult(p->interp);
  512. if( p->pScript && p->mask&TESTVFS_OPEN_MASK ){
  513. Tcl_Obj *pArg = Tcl_NewObj();
  514. Tcl_IncrRefCount(pArg);
  515. if( flags&SQLITE_OPEN_MAIN_DB ){
  516. const char *z = &zName[strlen(zName)+1];
  517. while( *z ){
  518. Tcl_ListObjAppendElement(0, pArg, Tcl_NewStringObj(z, -1));
  519. z += strlen(z) + 1;
  520. Tcl_ListObjAppendElement(0, pArg, Tcl_NewStringObj(z, -1));
  521. z += strlen(z) + 1;
  522. }
  523. }
  524. tvfsExecTcl(p, "xOpen", Tcl_NewStringObj(pFd->zFilename, -1), pArg, 0, 0);
  525. Tcl_DecrRefCount(pArg);
  526. if( tvfsResultCode(p, &rc) ){
  527. if( rc!=SQLITE_OK ) return rc;
  528. }else{
  529. pId = Tcl_GetObjResult(p->interp);
  530. }
  531. }
  532. if( (p->mask&TESTVFS_OPEN_MASK) && tvfsInjectIoerr(p) ) return SQLITE_IOERR;
  533. if( tvfsInjectCantopenerr(p) ) return SQLITE_CANTOPEN;
  534. if( tvfsInjectFullerr(p) ) return SQLITE_FULL;
  535. if( !pId ){
  536. pId = Tcl_NewStringObj("anon", -1);
  537. }
  538. Tcl_IncrRefCount(pId);
  539. pFd->pShmId = pId;
  540. Tcl_ResetResult(p->interp);
  541. rc = sqlite3OsOpen(PARENTVFS(pVfs), zName, pFd->pReal, flags, pOutFlags);
  542. if( pFd->pReal->pMethods ){
  543. sqlite3_io_methods *pMethods;
  544. int nByte;
  545. if( pVfs->iVersion>1 ){
  546. nByte = sizeof(sqlite3_io_methods);
  547. }else{
  548. nByte = offsetof(sqlite3_io_methods, xShmMap);
  549. }
  550. pMethods = (sqlite3_io_methods *)ckalloc(nByte);
  551. memcpy(pMethods, &tvfs_io_methods, nByte);
  552. pMethods->iVersion = pFd->pReal->pMethods->iVersion;
  553. if( pMethods->iVersion>pVfs->iVersion ){
  554. pMethods->iVersion = pVfs->iVersion;
  555. }
  556. if( pVfs->iVersion>1 && ((Testvfs *)pVfs->pAppData)->isNoshm ){
  557. pMethods->xShmUnmap = 0;
  558. pMethods->xShmLock = 0;
  559. pMethods->xShmBarrier = 0;
  560. pMethods->xShmMap = 0;
  561. }
  562. pFile->pMethods = pMethods;
  563. }
  564. return rc;
  565. }
  566. /*
  567. ** Delete the file located at zPath. If the dirSync argument is true,
  568. ** ensure the file-system modifications are synced to disk before
  569. ** returning.
  570. */
  571. static int tvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
  572. int rc = SQLITE_OK;
  573. Testvfs *p = (Testvfs *)pVfs->pAppData;
  574. if( p->pScript && p->mask&TESTVFS_DELETE_MASK ){
  575. tvfsExecTcl(p, "xDelete",
  576. Tcl_NewStringObj(zPath, -1), Tcl_NewIntObj(dirSync), 0, 0
  577. );
  578. tvfsResultCode(p, &rc);
  579. }
  580. if( rc==SQLITE_OK ){
  581. rc = sqlite3OsDelete(PARENTVFS(pVfs), zPath, dirSync);
  582. }
  583. return rc;
  584. }
  585. /*
  586. ** Test for access permissions. Return true if the requested permission
  587. ** is available, or false otherwise.
  588. */
  589. static int tvfsAccess(
  590. sqlite3_vfs *pVfs,
  591. const char *zPath,
  592. int flags,
  593. int *pResOut
  594. ){
  595. Testvfs *p = (Testvfs *)pVfs->pAppData;
  596. if( p->pScript && p->mask&TESTVFS_ACCESS_MASK ){
  597. int rc;
  598. char *zArg = 0;
  599. if( flags==SQLITE_ACCESS_EXISTS ) zArg = "SQLITE_ACCESS_EXISTS";
  600. if( flags==SQLITE_ACCESS_READWRITE ) zArg = "SQLITE_ACCESS_READWRITE";
  601. if( flags==SQLITE_ACCESS_READ ) zArg = "SQLITE_ACCESS_READ";
  602. tvfsExecTcl(p, "xAccess",
  603. Tcl_NewStringObj(zPath, -1), Tcl_NewStringObj(zArg, -1), 0, 0
  604. );
  605. if( tvfsResultCode(p, &rc) ){
  606. if( rc!=SQLITE_OK ) return rc;
  607. }else{
  608. Tcl_Interp *interp = p->interp;
  609. if( TCL_OK==Tcl_GetBooleanFromObj(0, Tcl_GetObjResult(interp), pResOut) ){
  610. return SQLITE_OK;
  611. }
  612. }
  613. }
  614. return sqlite3OsAccess(PARENTVFS(pVfs), zPath, flags, pResOut);
  615. }
  616. /*
  617. ** Populate buffer zOut with the full canonical pathname corresponding
  618. ** to the pathname in zPath. zOut is guaranteed to point to a buffer
  619. ** of at least (DEVSYM_MAX_PATHNAME+1) bytes.
  620. */
  621. static int tvfsFullPathname(
  622. sqlite3_vfs *pVfs,
  623. const char *zPath,
  624. int nOut,
  625. char *zOut
  626. ){
  627. Testvfs *p = (Testvfs *)pVfs->pAppData;
  628. if( p->pScript && p->mask&TESTVFS_FULLPATHNAME_MASK ){
  629. int rc;
  630. tvfsExecTcl(p, "xFullPathname", Tcl_NewStringObj(zPath, -1), 0, 0, 0);
  631. if( tvfsResultCode(p, &rc) ){
  632. if( rc!=SQLITE_OK ) return rc;
  633. }
  634. }
  635. return sqlite3OsFullPathname(PARENTVFS(pVfs), zPath, nOut, zOut);
  636. }
  637. #ifndef SQLITE_OMIT_LOAD_EXTENSION
  638. /*
  639. ** Open the dynamic library located at zPath and return a handle.
  640. */
  641. static void *tvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
  642. return sqlite3OsDlOpen(PARENTVFS(pVfs), zPath);
  643. }
  644. /*
  645. ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
  646. ** utf-8 string describing the most recent error encountered associated
  647. ** with dynamic libraries.
  648. */
  649. static void tvfsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
  650. sqlite3OsDlError(PARENTVFS(pVfs), nByte, zErrMsg);
  651. }
  652. /*
  653. ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
  654. */
  655. static void (*tvfsDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
  656. return sqlite3OsDlSym(PARENTVFS(pVfs), p, zSym);
  657. }
  658. /*
  659. ** Close the dynamic library handle pHandle.
  660. */
  661. static void tvfsDlClose(sqlite3_vfs *pVfs, void *pHandle){
  662. sqlite3OsDlClose(PARENTVFS(pVfs), pHandle);
  663. }
  664. #endif /* SQLITE_OMIT_LOAD_EXTENSION */
  665. /*
  666. ** Populate the buffer pointed to by zBufOut with nByte bytes of
  667. ** random data.
  668. */
  669. static int tvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
  670. return sqlite3OsRandomness(PARENTVFS(pVfs), nByte, zBufOut);
  671. }
  672. /*
  673. ** Sleep for nMicro microseconds. Return the number of microseconds
  674. ** actually slept.
  675. */
  676. static int tvfsSleep(sqlite3_vfs *pVfs, int nMicro){
  677. return sqlite3OsSleep(PARENTVFS(pVfs), nMicro);
  678. }
  679. /*
  680. ** Return the current time as a Julian Day number in *pTimeOut.
  681. */
  682. static int tvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
  683. return PARENTVFS(pVfs)->xCurrentTime(PARENTVFS(pVfs), pTimeOut);
  684. }
  685. static int tvfsShmOpen(sqlite3_file *pFile){
  686. Testvfs *p;
  687. int rc = SQLITE_OK; /* Return code */
  688. TestvfsBuffer *pBuffer; /* Buffer to open connection to */
  689. TestvfsFd *pFd; /* The testvfs file structure */
  690. pFd = tvfsGetFd(pFile);
  691. p = (Testvfs *)pFd->pVfs->pAppData;
  692. assert( 0==p->isFullshm );
  693. assert( pFd->pShmId && pFd->pShm==0 && pFd->pNext==0 );
  694. /* Evaluate the Tcl script:
  695. **
  696. ** SCRIPT xShmOpen FILENAME
  697. */
  698. Tcl_ResetResult(p->interp);
  699. if( p->pScript && p->mask&TESTVFS_SHMOPEN_MASK ){
  700. tvfsExecTcl(p, "xShmOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0, 0);
  701. if( tvfsResultCode(p, &rc) ){
  702. if( rc!=SQLITE_OK ) return rc;
  703. }
  704. }
  705. assert( rc==SQLITE_OK );
  706. if( p->mask&TESTVFS_SHMOPEN_MASK && tvfsInjectIoerr(p) ){
  707. return SQLITE_IOERR;
  708. }
  709. /* Search for a TestvfsBuffer. Create a new one if required. */
  710. for(pBuffer=p->pBuffer; pBuffer; pBuffer=pBuffer->pNext){
  711. if( 0==strcmp(pFd->zFilename, pBuffer->zFile) ) break;
  712. }
  713. if( !pBuffer ){
  714. int nByte = sizeof(TestvfsBuffer) + (int)strlen(pFd->zFilename) + 1;
  715. pBuffer = (TestvfsBuffer *)ckalloc(nByte);
  716. memset(pBuffer, 0, nByte);
  717. pBuffer->zFile = (char *)&pBuffer[1];
  718. strcpy(pBuffer->zFile, pFd->zFilename);
  719. pBuffer->pNext = p->pBuffer;
  720. p->pBuffer = pBuffer;
  721. }
  722. /* Connect the TestvfsBuffer to the new TestvfsShm handle and return. */
  723. pFd->pNext = pBuffer->pFile;
  724. pBuffer->pFile = pFd;
  725. pFd->pShm = pBuffer;
  726. return SQLITE_OK;
  727. }
  728. static void tvfsAllocPage(TestvfsBuffer *p, int iPage, int pgsz){
  729. assert( iPage<TESTVFS_MAX_PAGES );
  730. if( p->aPage[iPage]==0 ){
  731. p->aPage[iPage] = (u8 *)ckalloc(pgsz);
  732. memset(p->aPage[iPage], 0, pgsz);
  733. p->pgsz = pgsz;
  734. }
  735. }
  736. static int tvfsShmMap(
  737. sqlite3_file *pFile, /* Handle open on database file */
  738. int iPage, /* Page to retrieve */
  739. int pgsz, /* Size of pages */
  740. int isWrite, /* True to extend file if necessary */
  741. void volatile **pp /* OUT: Mapped memory */
  742. ){
  743. int rc = SQLITE_OK;
  744. TestvfsFd *pFd = tvfsGetFd(pFile);
  745. Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
  746. if( p->isFullshm ){
  747. return sqlite3OsShmMap(pFd->pReal, iPage, pgsz, isWrite, pp);
  748. }
  749. if( 0==pFd->pShm ){
  750. rc = tvfsShmOpen(pFile);
  751. if( rc!=SQLITE_OK ){
  752. return rc;
  753. }
  754. }
  755. if( p->pScript && p->mask&TESTVFS_SHMMAP_MASK ){
  756. Tcl_Obj *pArg = Tcl_NewObj();
  757. Tcl_IncrRefCount(pArg);
  758. Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(iPage));
  759. Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(pgsz));
  760. Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(isWrite));
  761. tvfsExecTcl(p, "xShmMap",
  762. Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, pArg, 0
  763. );
  764. tvfsResultCode(p, &rc);
  765. Tcl_DecrRefCount(pArg);
  766. }
  767. if( rc==SQLITE_OK && p->mask&TESTVFS_SHMMAP_MASK && tvfsInjectIoerr(p) ){
  768. rc = SQLITE_IOERR;
  769. }
  770. if( rc==SQLITE_OK && isWrite && !pFd->pShm->aPage[iPage] ){
  771. tvfsAllocPage(pFd->pShm, iPage, pgsz);
  772. }
  773. *pp = (void volatile *)pFd->pShm->aPage[iPage];
  774. return rc;
  775. }
  776. static int tvfsShmLock(
  777. sqlite3_file *pFile,
  778. int ofst,
  779. int n,
  780. int flags
  781. ){
  782. int rc = SQLITE_OK;
  783. TestvfsFd *pFd = tvfsGetFd(pFile);
  784. Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
  785. int nLock;
  786. char zLock[80];
  787. if( p->isFullshm ){
  788. return sqlite3OsShmLock(pFd->pReal, ofst, n, flags);
  789. }
  790. if( p->pScript && p->mask&TESTVFS_SHMLOCK_MASK ){
  791. sqlite3_snprintf(sizeof(zLock), zLock, "%d %d", ofst, n);
  792. nLock = (int)strlen(zLock);
  793. if( flags & SQLITE_SHM_LOCK ){
  794. strcpy(&zLock[nLock], " lock");
  795. }else{
  796. strcpy(&zLock[nLock], " unlock");
  797. }
  798. nLock += (int)strlen(&zLock[nLock]);
  799. if( flags & SQLITE_SHM_SHARED ){
  800. strcpy(&zLock[nLock], " shared");
  801. }else{
  802. strcpy(&zLock[nLock], " exclusive");
  803. }
  804. tvfsExecTcl(p, "xShmLock",
  805. Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId,
  806. Tcl_NewStringObj(zLock, -1), 0
  807. );
  808. tvfsResultCode(p, &rc);
  809. }
  810. if( rc==SQLITE_OK && p->mask&TESTVFS_SHMLOCK_MASK && tvfsInjectIoerr(p) ){
  811. rc = SQLITE_IOERR;
  812. }
  813. if( rc==SQLITE_OK ){
  814. int isLock = (flags & SQLITE_SHM_LOCK);
  815. int isExcl = (flags & SQLITE_SHM_EXCLUSIVE);
  816. u32 mask = (((1<<n)-1) << ofst);
  817. if( isLock ){
  818. TestvfsFd *p2;
  819. for(p2=pFd->pShm->pFile; p2; p2=p2->pNext){
  820. if( p2==pFd ) continue;
  821. if( (p2->excllock&mask) || (isExcl && p2->sharedlock&mask) ){
  822. rc = SQLITE_BUSY;
  823. break;
  824. }
  825. }
  826. if( rc==SQLITE_OK ){
  827. if( isExcl ) pFd->excllock |= mask;
  828. if( !isExcl ) pFd->sharedlock |= mask;
  829. }
  830. }else{
  831. if( isExcl ) pFd->excllock &= (~mask);
  832. if( !isExcl ) pFd->sharedlock &= (~mask);
  833. }
  834. }
  835. return rc;
  836. }
  837. static void tvfsShmBarrier(sqlite3_file *pFile){
  838. TestvfsFd *pFd = tvfsGetFd(pFile);
  839. Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
  840. if( p->isFullshm ){
  841. sqlite3OsShmBarrier(pFd->pReal);
  842. return;
  843. }
  844. if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){
  845. tvfsExecTcl(p, "xShmBarrier",
  846. Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0, 0
  847. );
  848. }
  849. }
  850. static int tvfsShmUnmap(
  851. sqlite3_file *pFile,
  852. int deleteFlag
  853. ){
  854. int rc = SQLITE_OK;
  855. TestvfsFd *pFd = tvfsGetFd(pFile);
  856. Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
  857. TestvfsBuffer *pBuffer = pFd->pShm;
  858. TestvfsFd **ppFd;
  859. if( p->isFullshm ){
  860. return sqlite3OsShmUnmap(pFd->pReal, deleteFlag);
  861. }
  862. if( !pBuffer ) return SQLITE_OK;
  863. assert( pFd->pShmId && pFd->pShm );
  864. if( p->pScript && p->mask&TESTVFS_SHMCLOSE_MASK ){
  865. tvfsExecTcl(p, "xShmUnmap",
  866. Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0, 0
  867. );
  868. tvfsResultCode(p, &rc);
  869. }
  870. for(ppFd=&pBuffer->pFile; *ppFd!=pFd; ppFd=&((*ppFd)->pNext));
  871. assert( (*ppFd)==pFd );
  872. *ppFd = pFd->pNext;
  873. pFd->pNext = 0;
  874. if( pBuffer->pFile==0 ){
  875. int i;
  876. TestvfsBuffer **pp;
  877. for(pp=&p->pBuffer; *pp!=pBuffer; pp=&((*pp)->pNext));
  878. *pp = (*pp)->pNext;
  879. for(i=0; pBuffer->aPage[i]; i++){
  880. ckfree((char *)pBuffer->aPage[i]);
  881. }
  882. ckfree((char *)pBuffer);
  883. }
  884. pFd->pShm = 0;
  885. return rc;
  886. }
  887. static int tvfsFetch(
  888. sqlite3_file *pFile,
  889. sqlite3_int64 iOfst,
  890. int iAmt,
  891. void **pp
  892. ){
  893. TestvfsFd *pFd = tvfsGetFd(pFile);
  894. return sqlite3OsFetch(pFd->pReal, iOfst, iAmt, pp);
  895. }
  896. static int tvfsUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *p){
  897. TestvfsFd *pFd = tvfsGetFd(pFile);
  898. return sqlite3OsUnfetch(pFd->pReal, iOfst, p);
  899. }
  900. static int testvfs_obj_cmd(
  901. ClientData cd,
  902. Tcl_Interp *interp,
  903. int objc,
  904. Tcl_Obj *CONST objv[]
  905. ){
  906. Testvfs *p = (Testvfs *)cd;
  907. enum DB_enum {
  908. CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT,
  909. CMD_DEVCHAR, CMD_SECTORSIZE, CMD_FULLERR, CMD_CANTOPENERR
  910. };
  911. struct TestvfsSubcmd {
  912. char *zName;
  913. enum DB_enum eCmd;
  914. } aSubcmd[] = {
  915. { "shm", CMD_SHM },
  916. { "delete", CMD_DELETE },
  917. { "filter", CMD_FILTER },
  918. { "ioerr", CMD_IOERR },
  919. { "fullerr", CMD_FULLERR },
  920. { "cantopenerr", CMD_CANTOPENERR },
  921. { "script", CMD_SCRIPT },
  922. { "devchar", CMD_DEVCHAR },
  923. { "sectorsize", CMD_SECTORSIZE },
  924. { 0, 0 }
  925. };
  926. int i;
  927. if( objc<2 ){
  928. Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
  929. return TCL_ERROR;
  930. }
  931. if( Tcl_GetIndexFromObjStruct(
  932. interp, objv[1], aSubcmd, sizeof(aSubcmd[0]), "subcommand", 0, &i)
  933. ){
  934. return TCL_ERROR;
  935. }
  936. Tcl_ResetResult(interp);
  937. switch( aSubcmd[i].eCmd ){
  938. case CMD_SHM: {
  939. Tcl_Obj *pObj;
  940. int i, rc;
  941. TestvfsBuffer *pBuffer;
  942. char *zName;
  943. if( objc!=3 && objc!=4 ){
  944. Tcl_WrongNumArgs(interp, 2, objv, "FILE ?VALUE?");
  945. return TCL_ERROR;
  946. }
  947. zName = ckalloc(p->pParent->mxPathname);
  948. rc = p->pParent->xFullPathname(
  949. p->pParent, Tcl_GetString(objv[2]),
  950. p->pParent->mxPathname, zName
  951. );
  952. if( rc!=SQLITE_OK ){
  953. Tcl_AppendResult(interp, "failed to get full path: ",
  954. Tcl_GetString(objv[2]), 0);
  955. ckfree(zName);
  956. return TCL_ERROR;
  957. }
  958. for(pBuffer=p->pBuffer; pBuffer; pBuffer=pBuffer->pNext){
  959. if( 0==strcmp(pBuffer->zFile, zName) ) break;
  960. }
  961. ckfree(zName);
  962. if( !pBuffer ){
  963. Tcl_AppendResult(interp, "no such file: ", Tcl_GetString(objv[2]), 0);
  964. return TCL_ERROR;
  965. }
  966. if( objc==4 ){
  967. int n;
  968. u8 *a = Tcl_GetByteArrayFromObj(objv[3], &n);
  969. int pgsz = pBuffer->pgsz;
  970. if( pgsz==0 ) pgsz = 65536;
  971. for(i=0; i*pgsz<n; i++){
  972. int nByte = pgsz;
  973. tvfsAllocPage(pBuffer, i, pgsz);
  974. if( n-i*pgsz<pgsz ){
  975. nByte = n;
  976. }
  977. memcpy(pBuffer->aPage[i], &a[i*pgsz], nByte);
  978. }
  979. }
  980. pObj = Tcl_NewObj();
  981. for(i=0; pBuffer->aPage[i]; i++){
  982. int pgsz = pBuffer->pgsz;
  983. if( pgsz==0 ) pgsz = 65536;
  984. Tcl_AppendObjToObj(pObj, Tcl_NewByteArrayObj(pBuffer->aPage[i], pgsz));
  985. }
  986. Tcl_SetObjResult(interp, pObj);
  987. break;
  988. }
  989. case CMD_FILTER: {
  990. static struct VfsMethod {
  991. char *zName;
  992. int mask;
  993. } vfsmethod [] = {
  994. { "xShmOpen", TESTVFS_SHMOPEN_MASK },
  995. { "xShmLock", TESTVFS_SHMLOCK_MASK },
  996. { "xShmBarrier", TESTVFS_SHMBARRIER_MASK },
  997. { "xShmUnmap", TESTVFS_SHMCLOSE_MASK },
  998. { "xShmMap", TESTVFS_SHMMAP_MASK },
  999. { "xSync", TESTVFS_SYNC_MASK },
  1000. { "xDelete", TESTVFS_DELETE_MASK },
  1001. { "xWrite", TESTVFS_WRITE_MASK },
  1002. { "xRead", TESTVFS_READ_MASK },
  1003. { "xTruncate", TESTVFS_TRUNCATE_MASK },
  1004. { "xOpen", TESTVFS_OPEN_MASK },
  1005. { "xClose", TESTVFS_CLOSE_MASK },
  1006. { "xAccess", TESTVFS_ACCESS_MASK },
  1007. { "xFullPathname", TESTVFS_FULLPATHNAME_MASK },
  1008. { "xUnlock", TESTVFS_UNLOCK_MASK },
  1009. };
  1010. Tcl_Obj **apElem = 0;
  1011. int nElem = 0;
  1012. int i;
  1013. int mask = 0;
  1014. if( objc!=3 ){
  1015. Tcl_WrongNumArgs(interp, 2, objv, "LIST");
  1016. return TCL_ERROR;
  1017. }
  1018. if( Tcl_ListObjGetElements(interp, objv[2], &nElem, &apElem) ){
  1019. return TCL_ERROR;
  1020. }
  1021. Tcl_ResetResult(interp);
  1022. for(i=0; i<nElem; i++){
  1023. int iMethod;
  1024. char *zElem = Tcl_GetString(apElem[i]);
  1025. for(iMethod=0; iMethod<ArraySize(vfsmethod); iMethod++){
  1026. if( strcmp(zElem, vfsmethod[iMethod].zName)==0 ){
  1027. mask |= vfsmethod[iMethod].mask;
  1028. break;
  1029. }
  1030. }
  1031. if( iMethod==ArraySize(vfsmethod) ){
  1032. Tcl_AppendResult(interp, "unknown method: ", zElem, 0);
  1033. return TCL_ERROR;
  1034. }
  1035. }
  1036. p->mask = mask;
  1037. break;
  1038. }
  1039. case CMD_SCRIPT: {
  1040. if( objc==3 ){
  1041. int nByte;
  1042. if( p->pScript ){
  1043. Tcl_DecrRefCount(p->pScript);
  1044. p->pScript = 0;
  1045. }
  1046. Tcl_GetStringFromObj(objv[2], &nByte);
  1047. if( nByte>0 ){
  1048. p->pScript = Tcl_DuplicateObj(objv[2]);
  1049. Tcl_IncrRefCount(p->pScript);
  1050. }
  1051. }else if( objc!=2 ){
  1052. Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?");
  1053. return TCL_ERROR;
  1054. }
  1055. Tcl_ResetResult(interp);
  1056. if( p->pScript ) Tcl_SetObjResult(interp, p->pScript);
  1057. break;
  1058. }
  1059. /*
  1060. ** TESTVFS ioerr ?IFAIL PERSIST?
  1061. **
  1062. ** Where IFAIL is an integer and PERSIST is boolean.
  1063. */
  1064. case CMD_CANTOPENERR:
  1065. case CMD_IOERR:
  1066. case CMD_FULLERR: {
  1067. TestFaultInject *pTest;
  1068. int iRet;
  1069. switch( aSubcmd[i].eCmd ){
  1070. case CMD_IOERR: pTest = &p->ioerr_err; break;
  1071. case CMD_FULLERR: pTest = &p->full_err; break;
  1072. case CMD_CANTOPENERR: pTest = &p->cantopen_err; break;
  1073. default: assert(0);
  1074. }
  1075. iRet = pTest->nFail;
  1076. pTest->nFail = 0;
  1077. pTest->eFault = 0;
  1078. pTest->iCnt = 0;
  1079. if( objc==4 ){
  1080. int iCnt, iPersist;
  1081. if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iCnt)
  1082. || TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &iPersist)
  1083. ){
  1084. return TCL_ERROR;
  1085. }
  1086. pTest->eFault = iPersist?FAULT_INJECT_PERSISTENT:FAULT_INJECT_TRANSIENT;
  1087. pTest->iCnt = iCnt;
  1088. }else if( objc!=2 ){
  1089. Tcl_WrongNumArgs(interp, 2, objv, "?CNT PERSIST?");
  1090. return TCL_ERROR;
  1091. }
  1092. Tcl_SetObjResult(interp, Tcl_NewIntObj(iRet));
  1093. break;
  1094. }
  1095. case CMD_DELETE: {
  1096. Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
  1097. break;
  1098. }
  1099. case CMD_DEVCHAR: {
  1100. struct DeviceFlag {
  1101. char *zName;
  1102. int iValue;
  1103. } aFlag[] = {
  1104. { "default", -1 },
  1105. { "atomic", SQLITE_IOCAP_ATOMIC },
  1106. { "atomic512", SQLITE_IOCAP_ATOMIC512 },
  1107. { "atomic1k", SQLITE_IOCAP_ATOMIC1K },
  1108. { "atomic2k", SQLITE_IOCAP_ATOMIC2K },
  1109. { "atomic4k", SQLITE_IOCAP_ATOMIC4K },
  1110. { "atomic8k", SQLITE_IOCAP_ATOMIC8K },
  1111. { "atomic16k", SQLITE_IOCAP_ATOMIC16K },
  1112. { "atomic32k", SQLITE_IOCAP_ATOMIC32K },
  1113. { "atomic64k", SQLITE_IOCAP_ATOMIC64K },
  1114. { "sequential", SQLITE_IOCAP_SEQUENTIAL },
  1115. { "safe_append", SQLITE_IOCAP_SAFE_APPEND },
  1116. { "undeletable_when_open", SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN },
  1117. { "powersafe_overwrite", SQLITE_IOCAP_POWERSAFE_OVERWRITE },
  1118. { 0, 0 }
  1119. };
  1120. Tcl_Obj *pRet;
  1121. int iFlag;
  1122. if( objc>3 ){
  1123. Tcl_WrongNumArgs(interp, 2, objv, "?ATTR-LIST?");
  1124. return TCL_ERROR;
  1125. }
  1126. if( objc==3 ){
  1127. int j;
  1128. int iNew = 0;
  1129. Tcl_Obj **flags = 0;
  1130. int nFlags = 0;
  1131. if( Tcl_ListObjGetElements(interp, objv[2], &nFlags, &flags) ){
  1132. return TCL_ERROR;
  1133. }
  1134. for(j=0; j<nFlags; j++){
  1135. int idx = 0;
  1136. if( Tcl_GetIndexFromObjStruct(interp, flags[j], aFlag,
  1137. sizeof(aFlag[0]), "flag", 0, &idx)
  1138. ){
  1139. return TCL_ERROR;
  1140. }
  1141. if( aFlag[idx].iValue<0 && nFlags>1 ){
  1142. Tcl_AppendResult(interp, "bad flags: ", Tcl_GetString(objv[2]), 0);
  1143. return TCL_ERROR;
  1144. }
  1145. iNew |= aFlag[idx].iValue;
  1146. }
  1147. p->iDevchar = iNew| 0x10000000;
  1148. }
  1149. pRet = Tcl_NewObj();
  1150. for(iFlag=0; iFlag<sizeof(aFlag)/sizeof(aFlag[0]); iFlag++){
  1151. if( p->iDevchar & aFlag[iFlag].iValue ){
  1152. Tcl_ListObjAppendElement(
  1153. interp, pRet, Tcl_NewStringObj(aFlag[iFlag].zName, -1)
  1154. );
  1155. }
  1156. }
  1157. Tcl_SetObjResult(interp, pRet);
  1158. break;
  1159. }
  1160. case CMD_SECTORSIZE: {
  1161. if( objc>3 ){
  1162. Tcl_WrongNumArgs(interp, 2, objv, "?VALUE?");
  1163. return TCL_ERROR;
  1164. }
  1165. if( objc==3 ){
  1166. int iNew = 0;
  1167. if( Tcl_GetIntFromObj(interp, objv[2], &iNew) ){
  1168. return TCL_ERROR;
  1169. }
  1170. p->iSectorsize = iNew;
  1171. }
  1172. Tcl_SetObjResult(interp, Tcl_NewIntObj(p->iSectorsize));
  1173. break;
  1174. }
  1175. }
  1176. return TCL_OK;
  1177. }
  1178. static void testvfs_obj_del(ClientData cd){
  1179. Testvfs *p = (Testvfs *)cd;
  1180. if( p->pScript ) Tcl_DecrRefCount(p->pScript);
  1181. sqlite3_vfs_unregister(p->pVfs);
  1182. ckfree((char *)p->pVfs);
  1183. ckfree((char *)p);
  1184. }
  1185. /*
  1186. ** Usage: testvfs VFSNAME ?SWITCHES?
  1187. **
  1188. ** Switches are:
  1189. **
  1190. ** -noshm BOOLEAN (True to omit shm methods. Default false)
  1191. ** -default BOOLEAN (True to make the vfs default. Default false)
  1192. **
  1193. ** This command creates two things when it is invoked: an SQLite VFS, and
  1194. ** a Tcl command. Both are named VFSNAME. The VFS is installed. It is not
  1195. ** installed as the default VFS.
  1196. **
  1197. ** The VFS passes all file I/O calls through to the underlying VFS.
  1198. **
  1199. ** Whenever the xShmMap method of the VFS
  1200. ** is invoked, the SCRIPT is executed as follows:
  1201. **
  1202. ** SCRIPT xShmMap FILENAME ID
  1203. **
  1204. ** The value returned by the invocation of SCRIPT above is interpreted as
  1205. ** an SQLite error code and returned to SQLite. Either a symbolic
  1206. ** "SQLITE_OK" or numeric "0" value may be returned.
  1207. **
  1208. ** The contents of the shared-memory buffer associated with a given file
  1209. ** may be read and set using the following command:
  1210. **
  1211. ** VFSNAME shm FILENAME ?NEWVALUE?
  1212. **
  1213. ** When the xShmLock method is invoked by SQLite, the following script is
  1214. ** run:
  1215. **
  1216. ** SCRIPT xShmLock FILENAME ID LOCK
  1217. **
  1218. ** where LOCK is of the form "OFFSET NBYTE lock/unlock shared/exclusive"
  1219. */
  1220. static int testvfs_cmd(
  1221. ClientData cd,
  1222. Tcl_Interp *interp,
  1223. int objc,
  1224. Tcl_Obj *CONST objv[]
  1225. ){
  1226. static sqlite3_vfs tvfs_vfs = {
  1227. 3, /* iVersion */
  1228. 0, /* szOsFile */
  1229. 0, /* mxPathname */
  1230. 0, /* pNext */
  1231. 0, /* zName */
  1232. 0, /* pAppData */
  1233. tvfsOpen, /* xOpen */
  1234. tvfsDelete, /* xDelete */
  1235. tvfsAccess, /* xAccess */
  1236. tvfsFullPathname, /* xFullPathname */
  1237. #ifndef SQLITE_OMIT_LOAD_EXTENSION
  1238. tvfsDlOpen, /* xDlOpen */
  1239. tvfsDlError, /* xDlError */
  1240. tvfsDlSym, /* xDlSym */
  1241. tvfsDlClose, /* xDlClose */
  1242. #else
  1243. 0, /* xDlOpen */
  1244. 0, /* xDlError */
  1245. 0, /* xDlSym */
  1246. 0, /* xDlClose */
  1247. #endif /* SQLITE_OMIT_LOAD_EXTENSION */
  1248. tvfsRandomness, /* xRandomness */
  1249. tvfsSleep, /* xSleep */
  1250. tvfsCurrentTime, /* xCurrentTime */
  1251. 0, /* xGetLastError */
  1252. 0, /* xCurrentTimeInt64 */
  1253. 0, /* xSetSystemCall */
  1254. 0, /* xGetSystemCall */
  1255. 0, /* xNextSystemCall */
  1256. };
  1257. Testvfs *p; /* New object */
  1258. sqlite3_vfs *pVfs; /* New VFS */
  1259. char *zVfs;
  1260. int nByte; /* Bytes of space to allocate at p */
  1261. int i;
  1262. int isNoshm = 0; /* True if -noshm is passed */
  1263. int isFullshm = 0; /* True if -fullshm is passed */
  1264. int isDefault = 0; /* True if -default is passed */
  1265. int szOsFile = 0; /* Value passed to -szosfile */
  1266. int mxPathname = -1; /* Value passed to -mxpathname */
  1267. int iVersion = 3; /* Value passed to -iversion */
  1268. if( objc<2 || 0!=(objc%2) ) goto bad_args;
  1269. for(i=2; i<objc; i += 2){
  1270. int nSwitch;
  1271. char *zSwitch;
  1272. zSwitch = Tcl_GetStringFromObj(objv[i], &nSwitch);
  1273. if( nSwitch>2 && 0==strncmp("-noshm", zSwitch, nSwitch) ){
  1274. if( Tcl_GetBooleanFromObj(interp, objv[i+1], &isNoshm) ){
  1275. return TCL_ERROR;
  1276. }
  1277. if( isNoshm ) isFullshm = 0;
  1278. }
  1279. else if( nSwitch>2 && 0==strncmp("-default", zSwitch, nSwitch) ){
  1280. if( Tcl_GetBooleanFromObj(interp, objv[i+1], &isDefault) ){
  1281. return TCL_ERROR;
  1282. }
  1283. }
  1284. else if( nSwitch>2 && 0==strncmp("-szosfile", zSwitch, nSwitch) ){
  1285. if( Tcl_GetIntFromObj(interp, objv[i+1], &szOsFile) ){
  1286. return TCL_ERROR;
  1287. }
  1288. }
  1289. else if( nSwitch>2 && 0==strncmp("-mxpathname", zSwitch, nSwitch) ){
  1290. if( Tcl_GetIntFromObj(interp, objv[i+1], &mxPathname) ){
  1291. return TCL_ERROR;
  1292. }
  1293. }
  1294. else if( nSwitch>2 && 0==strncmp("-iversion", zSwitch, nSwitch) ){
  1295. if( Tcl_GetIntFromObj(interp, objv[i+1], &iVersion) ){
  1296. return TCL_ERROR;
  1297. }
  1298. }
  1299. else if( nSwitch>2 && 0==strncmp("-fullshm", zSwitch, nSwitch) ){
  1300. if( Tcl_GetBooleanFromObj(interp, objv[i+1], &isFullshm) ){
  1301. return TCL_ERROR;
  1302. }
  1303. if( isFullshm ) isNoshm = 0;
  1304. }
  1305. else{
  1306. goto bad_args;
  1307. }
  1308. }
  1309. if( szOsFile<sizeof(TestvfsFile) ){
  1310. szOsFile = sizeof(TestvfsFile);
  1311. }
  1312. zVfs = Tcl_GetString(objv[1]);
  1313. nByte = sizeof(Testvfs) + (int)strlen(zVfs)+1;
  1314. p = (Testvfs *)ckalloc(nByte);
  1315. memset(p, 0, nByte);
  1316. p->iDevchar = -1;
  1317. p->iSectorsize = -1;
  1318. /* Create the new object command before querying SQLite for a default VFS
  1319. ** to use for 'real' IO operations. This is because creating the new VFS
  1320. ** may delete an existing [testvfs] VFS of the same name. If such a VFS
  1321. ** is currently the default, the new [testvfs] may end up calling the
  1322. ** methods of a deleted object.
  1323. */
  1324. Tcl_CreateObjCommand(interp, zVfs, testvfs_obj_cmd, p, testvfs_obj_del);
  1325. p->pParent = sqlite3_vfs_find(0);
  1326. p->interp = interp;
  1327. p->zName = (char *)&p[1];
  1328. memcpy(p->zName, zVfs, strlen(zVfs)+1);
  1329. pVfs = (sqlite3_vfs *)ckalloc(sizeof(sqlite3_vfs));
  1330. memcpy(pVfs, &tvfs_vfs, sizeof(sqlite3_vfs));
  1331. pVfs->pAppData = (void *)p;
  1332. pVfs->iVersion = iVersion;
  1333. pVfs->zName = p->zName;
  1334. pVfs->mxPathname = p->pParent->mxPathname;
  1335. if( mxPathname>=0 && mxPathname<pVfs->mxPathname ){
  1336. pVfs->mxPathname = mxPathname;
  1337. }
  1338. pVfs->szOsFile = szOsFile;
  1339. p->pVfs = pVfs;
  1340. p->isNoshm = isNoshm;
  1341. p->isFullshm = isFullshm;
  1342. p->mask = TESTVFS_ALL_MASK;
  1343. sqlite3_vfs_register(pVfs, isDefault);
  1344. return TCL_OK;
  1345. bad_args:
  1346. Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-default BOOL? ?-mxpathname INT? ?-szosfile INT? ?-iversion INT?");
  1347. return TCL_ERROR;
  1348. }
  1349. int Sqlitetestvfs_Init(Tcl_Interp *interp){
  1350. Tcl_CreateObjCommand(interp, "testvfs", testvfs_cmd, 0, 0);
  1351. return TCL_OK;
  1352. }
  1353. #endif