blob: 0abf2353a9fba81ced059a6cac9c0ac680cfce5b [file] [log] [blame]
drh9c06c952005-11-26 00:25:00 +00001/*
2** 2004 May 22
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 code that modified the OS layer in order to simulate
14** the effect on the database file of an OS crash or power failure. This
15** is used to test the ability of SQLite to recover from those situations.
16*/
17#if SQLITE_TEST /* This file is used for the testing only */
18#include "sqliteInt.h"
drh9c06c952005-11-26 00:25:00 +000019#include "tcl.h"
20
drh198bf392006-01-06 21:52:49 +000021#ifndef SQLITE_OMIT_DISKIO /* This file is a no-op if disk I/O is disabled */
22
danielk197762079062007-08-15 17:08:46 +000023typedef struct CrashFile CrashFile;
24typedef struct CrashGlobal CrashGlobal;
danielk19770d24e6b2007-08-14 17:42:05 +000025typedef struct WriteBuffer WriteBuffer;
26
27/*
28** Method:
29**
30** This layer is implemented as a wrapper around the "real"
31** sqlite3_file object for the host system. Each time data is
32** written to the file object, instead of being written to the
33** underlying file, the write operation is stored in an in-memory
34** structure (type WriteBuffer). This structure is placed at the
35** end of a global ordered list (the write-list).
36**
37** When data is read from a file object, the requested region is
38** first retrieved from the real file. The write-list is then
39** traversed and data copied from any overlapping WriteBuffer
40** structures to the output buffer. i.e. a read() operation following
41** one or more write() operations works as expected, even if no
42** data has actually been written out to the real file.
43**
44** When a fsync() operation is performed, an operating system crash
45** may be simulated, in which case exit(-1) is called (the call to
46** xSync() never returns). Whether or not a crash is simulated,
47** the data associated with a subset of the WriteBuffer structures
48** stored in the write-list is written to the real underlying files
49** and the entries removed from the write-list. If a crash is simulated,
50** a subset of the buffers may be corrupted before the data is written.
51**
52** The exact subset of the write-list written and/or corrupted is
53** determined by the simulated device characteristics and sector-size.
54**
55** "Normal" mode:
56**
57** Normal mode is used when the simulated device has none of the
58** SQLITE_IOCAP_XXX flags set.
59**
60** In normal mode, if the fsync() is not a simulated crash, the
61** write-list is traversed from beginning to end. Each WriteBuffer
62** structure associated with the file handle used to call xSync()
63** is written to the real file and removed from the write-list.
64**
65** If a crash is simulated, one of the following takes place for
66** each WriteBuffer in the write-list, regardless of which
67** file-handle it is associated with:
68**
69** 1. The buffer is correctly written to the file, just as if
70** a crash were not being simulated.
71**
72** 2. Nothing is done.
73**
74** 3. Garbage data is written to all sectors of the file that
75** overlap the region specified by the WriteBuffer. Or garbage
76** data is written to some contiguous section within the
77** overlapped sectors.
78**
79** Device Characteristic flag handling:
80**
81** If the IOCAP_ATOMIC flag is set, then option (3) above is
82** never selected.
83**
84** If the IOCAP_ATOMIC512 flag is set, and the WriteBuffer represents
85** an aligned write() of an integer number of 512 byte regions, then
86** option (3) above is never selected. Instead, each 512 byte region
87** is either correctly written or left completely untouched. Similar
88** logic governs the behaviour if any of the other ATOMICXXX flags
89** is set.
90**
91** If either the IOCAP_SAFEAPPEND or IOCAP_SEQUENTIAL flags are set
92** and a crash is being simulated, then an entry of the write-list is
93** selected at random. Everything in the list after the selected entry
94** is discarded before processing begins.
95**
96** If IOCAP_SEQUENTIAL is set and a crash is being simulated, option
97** (1) is selected for all write-list entries except the last. If a
98** crash is not being simulated, then all entries in the write-list
99** that occur before at least one write() on the file-handle specified
100** as part of the xSync() are written to their associated real files.
101**
102** If IOCAP_SAFEAPPEND is set and the first byte written by the write()
103** operation is one byte past the current end of the file, then option
104** (1) is always selected.
105*/
danielk197762079062007-08-15 17:08:46 +0000106
107/*
108** Each write operation in the write-list is represented by an instance
109** of the following structure.
110**
111** If zBuf is 0, then this structure represents a call to xTruncate(),
112** not xWrite(). In that case, iOffset is the size that the file is
113** truncated to.
114*/
danielk19770d24e6b2007-08-14 17:42:05 +0000115struct WriteBuffer {
danielk197762079062007-08-15 17:08:46 +0000116 i64 iOffset; /* Byte offset of the start of this write() */
117 int nBuf; /* Number of bytes written */
118 u8 *zBuf; /* Pointer to copy of written data */
119 CrashFile *pFile; /* File this write() applies to */
120
121 WriteBuffer *pNext; /* Next in CrashGlobal.pWriteList */
danielk19770d24e6b2007-08-14 17:42:05 +0000122};
123
danielk197762079062007-08-15 17:08:46 +0000124struct CrashFile {
125 const sqlite3_io_methods *pMethod; /* Must be first */
126 sqlite3_file *pRealFile; /* Underlying "real" file handle */
danielk19771e536952007-08-16 10:09:01 +0000127 char *zName;
danielk1977967a4a12007-08-20 14:23:44 +0000128
danielk1977f1da17a2007-08-21 13:07:46 +0000129 /* Cache of the entire file. This is used to speed up OsRead() and
130 ** OsFileSize() calls. Although both could be done by traversing the
131 ** write-list, in practice this is impractically slow.
132 */
danielk1977967a4a12007-08-20 14:23:44 +0000133 int iSize; /* Size of file in bytes */
134 int nData; /* Size of buffer allocated at zData */
135 u8 *zData; /* Buffer containing file contents */
drh9c06c952005-11-26 00:25:00 +0000136};
137
danielk197762079062007-08-15 17:08:46 +0000138struct CrashGlobal {
139 WriteBuffer *pWriteList; /* Head of write-list */
danielk1977967a4a12007-08-20 14:23:44 +0000140 WriteBuffer *pWriteListEnd; /* End of write-list */
drh9c06c952005-11-26 00:25:00 +0000141
danielk197762079062007-08-15 17:08:46 +0000142 int iSectorSize; /* Value of simulated sector size */
143 int iDeviceCharacteristics; /* Value of simulated device characteristics */
drh9c06c952005-11-26 00:25:00 +0000144
danielk197762079062007-08-15 17:08:46 +0000145 int iCrash; /* Crash on the iCrash'th call to xSync() */
146 char zCrashFile[500]; /* Crash during an xSync() on this file */
147};
drh9c06c952005-11-26 00:25:00 +0000148
danielk1977967a4a12007-08-20 14:23:44 +0000149static CrashGlobal g = {0, 0, SQLITE_DEFAULT_SECTOR_SIZE, 0, 0};
drh9c06c952005-11-26 00:25:00 +0000150
151/*
drh66560ad2006-01-06 14:32:19 +0000152** Set this global variable to 1 to enable crash testing.
153*/
danielk1977967a4a12007-08-20 14:23:44 +0000154static int sqlite3CrashTestEnable = 0;
drh66560ad2006-01-06 14:32:19 +0000155
156/*
danielk197762079062007-08-15 17:08:46 +0000157** Flush the write-list as if xSync() had been called on file handle
158** pFile. If isCrash is true, simulate a crash.
drh9c06c952005-11-26 00:25:00 +0000159*/
danielk197762079062007-08-15 17:08:46 +0000160static int writeListSync(CrashFile *pFile, int isCrash){
161 int rc = SQLITE_OK;
162 int iDc = g.iDeviceCharacteristics;
danielk1977967a4a12007-08-20 14:23:44 +0000163 i64 iSize;
drh66560ad2006-01-06 14:32:19 +0000164
danielk197762079062007-08-15 17:08:46 +0000165 WriteBuffer *pWrite;
166 WriteBuffer **ppPtr;
drh66560ad2006-01-06 14:32:19 +0000167
danielk197762079062007-08-15 17:08:46 +0000168 /* Set pFinal to point to the last element of the write-list that
169 ** is associated with file handle pFile.
170 */
171 WriteBuffer *pFinal = 0;
172 if( !isCrash ){
173 for(pWrite=g.pWriteList; pWrite; pWrite=pWrite->pNext){
174 if( pWrite->pFile==pFile ){
175 pFinal = pWrite;
176 }
177 }
drh1a235932005-11-29 18:37:15 +0000178 }
drh66560ad2006-01-06 14:32:19 +0000179
danielk1977967a4a12007-08-20 14:23:44 +0000180 sqlite3OsFileSize((sqlite3_file *)pFile, &iSize);
181
danielk197762079062007-08-15 17:08:46 +0000182 ppPtr = &g.pWriteList;
183 for(pWrite=*ppPtr; rc==SQLITE_OK && pWrite; pWrite=*ppPtr){
danielk1977967a4a12007-08-20 14:23:44 +0000184 sqlite3_file *pRealFile = pWrite->pFile->pRealFile;
danielk197762079062007-08-15 17:08:46 +0000185
186 /* (eAction==1) -> write block out normally,
187 ** (eAction==2) -> do nothing,
188 ** (eAction==3) -> trash sectors.
189 */
190 int eAction = 0;
191 if( !isCrash ){
192 eAction = 2;
193 if( (pWrite->pFile==pFile || iDc&SQLITE_IOCAP_SEQUENTIAL) ){
194 eAction = 1;
195 }
196 }else{
197 char random;
198 sqlite3Randomness(1, &random);
199
200 if( iDc&SQLITE_IOCAP_ATOMIC || pWrite->zBuf==0 ){
201 random &= 0x01;
202 }
203
204 if( (random&0x06)==0x06 ){
205 eAction = 3;
206 }else{
207 eAction = ((random&0x01)?2:1);
208 }
209 }
210
211 switch( eAction ){
212 case 1: { /* Write out correctly */
213 if( pWrite->zBuf ){
214 rc = sqlite3OsWrite(
danielk1977967a4a12007-08-20 14:23:44 +0000215 pRealFile, pWrite->zBuf, pWrite->nBuf, pWrite->iOffset
danielk197762079062007-08-15 17:08:46 +0000216 );
217 }else{
danielk1977967a4a12007-08-20 14:23:44 +0000218 rc = sqlite3OsTruncate(pRealFile, pWrite->iOffset);
danielk197762079062007-08-15 17:08:46 +0000219 }
220 *ppPtr = pWrite->pNext;
drh17435752007-08-16 04:30:38 +0000221 sqlite3_free(pWrite);
danielk197762079062007-08-15 17:08:46 +0000222 break;
223 }
224 case 2: { /* Do nothing */
225 ppPtr = &pWrite->pNext;
226 break;
227 }
228 case 3: { /* Trash sectors */
229 u8 *zGarbage;
danielk1977967a4a12007-08-20 14:23:44 +0000230 int iFirst = (pWrite->iOffset/g.iSectorSize);
231 int iLast = (pWrite->iOffset+pWrite->nBuf-1)/g.iSectorSize;
232
233 assert(pWrite->zBuf);
danielk197762079062007-08-15 17:08:46 +0000234
drh17435752007-08-16 04:30:38 +0000235 zGarbage = sqlite3_malloc(g.iSectorSize);
danielk197762079062007-08-15 17:08:46 +0000236 if( zGarbage ){
237 sqlite3_int64 i;
238 for(i=iFirst; rc==SQLITE_OK && i<=iLast; i++){
239 sqlite3Randomness(g.iSectorSize, zGarbage);
240 rc = sqlite3OsWrite(
danielk1977967a4a12007-08-20 14:23:44 +0000241 pRealFile, zGarbage, g.iSectorSize, i*g.iSectorSize
danielk197762079062007-08-15 17:08:46 +0000242 );
243 }
drh17435752007-08-16 04:30:38 +0000244 sqlite3_free(zGarbage);
danielk197762079062007-08-15 17:08:46 +0000245 }else{
246 rc = SQLITE_NOMEM;
247 }
248
249 ppPtr = &pWrite->pNext;
250 break;
251 }
252
253 default:
254 assert(!"Cannot happen");
255 }
256
257 if( pWrite==pFinal ) break;
drh1a235932005-11-29 18:37:15 +0000258 }
danielk197762079062007-08-15 17:08:46 +0000259
260 if( rc==SQLITE_OK && isCrash ){
261 exit(-1);
262 }
263
danielk1977967a4a12007-08-20 14:23:44 +0000264 for(pWrite=g.pWriteList; pWrite && pWrite->pNext; pWrite=pWrite->pNext);
265 g.pWriteListEnd = pWrite;
266
drh1a235932005-11-29 18:37:15 +0000267 return rc;
drh9c06c952005-11-26 00:25:00 +0000268}
269
270/*
danielk197762079062007-08-15 17:08:46 +0000271** Add an entry to the end of the write-list.
drh18839212005-11-26 03:43:23 +0000272*/
danielk197762079062007-08-15 17:08:46 +0000273static int writeListAppend(
274 sqlite3_file *pFile,
275 sqlite3_int64 iOffset,
276 const u8 *zBuf,
277 int nBuf
278){
279 WriteBuffer *pNew;
280
281 assert((zBuf && nBuf) || (!nBuf && !zBuf));
282
danielk1977b4b47412007-08-17 15:53:36 +0000283 pNew = (WriteBuffer *)sqlite3MallocZero(sizeof(WriteBuffer) + nBuf);
danielk197762079062007-08-15 17:08:46 +0000284 pNew->iOffset = iOffset;
285 pNew->nBuf = nBuf;
286 pNew->pFile = (CrashFile *)pFile;
287 if( zBuf ){
288 pNew->zBuf = (u8 *)&pNew[1];
289 memcpy(pNew->zBuf, zBuf, nBuf);
290 }
291
292 if( g.pWriteList ){
danielk1977967a4a12007-08-20 14:23:44 +0000293 assert(g.pWriteListEnd);
294 g.pWriteListEnd->pNext = pNew;
danielk197762079062007-08-15 17:08:46 +0000295 }else{
296 g.pWriteList = pNew;
297 }
danielk1977967a4a12007-08-20 14:23:44 +0000298 g.pWriteListEnd = pNew;
danielk197762079062007-08-15 17:08:46 +0000299
drh1a235932005-11-29 18:37:15 +0000300 return SQLITE_OK;
301}
302
303/*
danielk197762079062007-08-15 17:08:46 +0000304** Close a crash-file.
drh1a235932005-11-29 18:37:15 +0000305*/
danielk19771e536952007-08-16 10:09:01 +0000306static int cfClose(sqlite3_file *pFile){
danielk197762079062007-08-15 17:08:46 +0000307 CrashFile *pCrash = (CrashFile *)pFile;
308 writeListSync(pCrash, 0);
danielk1977f1da17a2007-08-21 13:07:46 +0000309 sqlite3OsClose(pCrash->pRealFile);
danielk197762079062007-08-15 17:08:46 +0000310 return SQLITE_OK;
drh1a235932005-11-29 18:37:15 +0000311}
312
313/*
danielk197762079062007-08-15 17:08:46 +0000314** Read data from a crash-file.
drh1a235932005-11-29 18:37:15 +0000315*/
danielk19771e536952007-08-16 10:09:01 +0000316static int cfRead(
317 sqlite3_file *pFile,
318 void *zBuf,
319 int iAmt,
320 sqlite_int64 iOfst
321){
danielk197762079062007-08-15 17:08:46 +0000322 CrashFile *pCrash = (CrashFile *)pFile;
323 sqlite3_int64 iSize;
danielk197762079062007-08-15 17:08:46 +0000324 WriteBuffer *pWrite;
325
326 /* Check the file-size to see if this is a short-read */
danielk1977967a4a12007-08-20 14:23:44 +0000327 if( pCrash->iSize<(iOfst+iAmt) ){
danielk197762079062007-08-15 17:08:46 +0000328 return SQLITE_IOERR_SHORT_READ;
329 }
330
danielk1977967a4a12007-08-20 14:23:44 +0000331 memcpy(zBuf, &pCrash->zData[iOfst], iAmt);
332 return SQLITE_OK;
drh18839212005-11-26 03:43:23 +0000333}
334
335/*
danielk197762079062007-08-15 17:08:46 +0000336** Write data to a crash-file.
danielk1977b4721172007-03-19 05:54:48 +0000337*/
danielk19771e536952007-08-16 10:09:01 +0000338static int cfWrite(
339 sqlite3_file *pFile,
340 const void *zBuf,
341 int iAmt,
342 sqlite_int64 iOfst
343){
danielk1977967a4a12007-08-20 14:23:44 +0000344 CrashFile *pCrash = (CrashFile *)pFile;
345 if( iAmt+iOfst>pCrash->iSize ){
346 pCrash->iSize = iAmt+iOfst;
347 }
348 while( pCrash->iSize>pCrash->nData ){
349 char *zNew;
350 int nNew = (pCrash->nData*2) + 4096;
351 zNew = (char *)sqlite3_realloc(pCrash->zData, nNew);
352 if( !zNew ){
353 return SQLITE_NOMEM;
354 }
355 memset(&zNew[pCrash->nData], 0, nNew-pCrash->nData);
356 pCrash->nData = nNew;
357 pCrash->zData = zNew;
358 }
359 memcpy(&pCrash->zData[iOfst], zBuf, iAmt);
danielk197762079062007-08-15 17:08:46 +0000360 return writeListAppend(pFile, iOfst, zBuf, iAmt);
danielk1977b4721172007-03-19 05:54:48 +0000361}
362
363/*
danielk197762079062007-08-15 17:08:46 +0000364** Truncate a crash-file.
drh054889e2005-11-30 03:20:31 +0000365*/
danielk19771e536952007-08-16 10:09:01 +0000366static int cfTruncate(sqlite3_file *pFile, sqlite_int64 size){
danielk1977967a4a12007-08-20 14:23:44 +0000367 CrashFile *pCrash = (CrashFile *)pFile;
368 assert(size>=0);
369 if( pCrash->iSize>size ){
370 pCrash->iSize = size;
371 }
danielk197762079062007-08-15 17:08:46 +0000372 return writeListAppend(pFile, size, 0, 0);
373}
374
375/*
376** Sync a crash-file.
377*/
danielk19771e536952007-08-16 10:09:01 +0000378static int cfSync(sqlite3_file *pFile, int flags){
danielk197762079062007-08-15 17:08:46 +0000379 CrashFile *pCrash = (CrashFile *)pFile;
380 int isCrash = 0;
381
danielk1977967a4a12007-08-20 14:23:44 +0000382 const char *zName = pCrash->zName;
383 const char *zCrashFile = g.zCrashFile;
384 int nName = strlen(zName);
385 int nCrashFile = strlen(zCrashFile);
386
387 if( nCrashFile>0 && zCrashFile[nCrashFile-1]=='*' ){
388 nCrashFile--;
389 if( nName>nCrashFile ) nName = nCrashFile;
390 }
391
392 if( nName==nCrashFile && 0==memcmp(zName, zCrashFile, nName) ){
393 if( (--g.iCrash)==0 ) isCrash = 1;
danielk197762079062007-08-15 17:08:46 +0000394 }
395
396 return writeListSync(pCrash, isCrash);
397}
398
399/*
400** Return the current file-size of the crash-file.
401*/
danielk19771e536952007-08-16 10:09:01 +0000402static int cfFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
danielk197762079062007-08-15 17:08:46 +0000403 CrashFile *pCrash = (CrashFile *)pFile;
danielk1977967a4a12007-08-20 14:23:44 +0000404 *pSize = (i64)pCrash->iSize;
danielk197762079062007-08-15 17:08:46 +0000405 return SQLITE_OK;
406}
407
408/*
409** Calls related to file-locks are passed on to the real file handle.
410*/
danielk19771e536952007-08-16 10:09:01 +0000411static int cfLock(sqlite3_file *pFile, int eLock){
danielk197762079062007-08-15 17:08:46 +0000412 return sqlite3OsLock(((CrashFile *)pFile)->pRealFile, eLock);
413}
danielk19771e536952007-08-16 10:09:01 +0000414static int cfUnlock(sqlite3_file *pFile, int eLock){
danielk197762079062007-08-15 17:08:46 +0000415 return sqlite3OsUnlock(((CrashFile *)pFile)->pRealFile, eLock);
416}
danielk19771e536952007-08-16 10:09:01 +0000417static int cfCheckReservedLock(sqlite3_file *pFile){
danielk197762079062007-08-15 17:08:46 +0000418 return sqlite3OsCheckReservedLock(((CrashFile *)pFile)->pRealFile);
419}
danielk1977967a4a12007-08-20 14:23:44 +0000420static int cfLockState(sqlite3_file *pFile){
421 return sqlite3OsLockState(((CrashFile *)pFile)->pRealFile);
422}
danielk19771e536952007-08-16 10:09:01 +0000423static int cfBreakLock(sqlite3_file *pFile){
danielk197762079062007-08-15 17:08:46 +0000424 return sqlite3OsBreakLock(((CrashFile *)pFile)->pRealFile);
425}
426
427/*
428** The xSectorSize() and xDeviceCharacteristics() functions return
429** the global values configured by the [sqlite_crashparams] tcl
430* interface.
431*/
danielk19771e536952007-08-16 10:09:01 +0000432static int cfSectorSize(sqlite3_file *pFile){
danielk197762079062007-08-15 17:08:46 +0000433 return g.iSectorSize;
434}
danielk19771e536952007-08-16 10:09:01 +0000435static int cfDeviceCharacteristics(sqlite3_file *pFile){
danielk197762079062007-08-15 17:08:46 +0000436 return g.iDeviceCharacteristics;
437}
438
439static const sqlite3_io_methods CrashFileVtab = {
440 1, /* iVersion */
441 cfClose, /* xClose */
442 cfRead, /* xRead */
443 cfWrite, /* xWrite */
444 cfTruncate, /* xTruncate */
445 cfSync, /* xSync */
446 cfFileSize, /* xFileSize */
447 cfLock, /* xLock */
448 cfUnlock, /* xUnlock */
449 cfCheckReservedLock, /* xCheckReservedLock */
450 cfBreakLock, /* xBreakLock */
danielk1977967a4a12007-08-20 14:23:44 +0000451 cfLockState, /* xLockState */
danielk197762079062007-08-15 17:08:46 +0000452 cfSectorSize, /* xSectorSize */
453 cfDeviceCharacteristics /* xDeviceCharacteristics */
drh054889e2005-11-30 03:20:31 +0000454};
455
drh054889e2005-11-30 03:20:31 +0000456/*
drhd677b3d2007-08-20 22:48:41 +0000457** Application data for the crash VFS
458*/
459struct crashAppData {
danielk1977f1da17a2007-08-21 13:07:46 +0000460 sqlite3_vfs *pOrig; /* Wrapped vfs structure */
drhd677b3d2007-08-20 22:48:41 +0000461};
462
463/*
danielk197762079062007-08-15 17:08:46 +0000464** Open a crash-file file handle. The vfs pVfs is used to open
465** the underlying real file.
danielk1977967a4a12007-08-20 14:23:44 +0000466**
467** The caller will have allocated pVfs->szOsFile bytes of space
468** at pFile. This file uses this space for the CrashFile structure
469** and allocates space for the "real" file structure using
470** sqlite3_malloc(). The assumption here is (pVfs->szOsFile) is
471** equal or greater than sizeof(CrashFile).
drh054889e2005-11-30 03:20:31 +0000472*/
danielk1977f1da17a2007-08-21 13:07:46 +0000473static int cfOpen(
474 void *pAppData,
danielk197762079062007-08-15 17:08:46 +0000475 const char *zName,
476 sqlite3_file *pFile,
477 int flags,
478 int *pOutFlags
479){
danielk1977f1da17a2007-08-21 13:07:46 +0000480 sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
danielk1977967a4a12007-08-20 14:23:44 +0000481 int rc;
danielk1977f1da17a2007-08-21 13:07:46 +0000482 CrashFile *pWrapper = (CrashFile *)pFile;
483 sqlite3_file *pReal = &pWrapper[1];
484
485 memset(pWrapper, 0, sizeof(CrashFile));
486 rc = sqlite3OsOpen(pVfs, zName, pReal, flags, pOutFlags);
487
488 if( rc==SQLITE_OK ){
489 i64 iSize;
490 pWrapper->pMethod = &CrashFileVtab;
491 pWrapper->zName = (char *)zName;
492 pWrapper->pRealFile = pReal;
493 rc = sqlite3OsFileSize(pReal, &iSize);
494 pWrapper->iSize = (int)iSize;
495 }
496 if( rc==SQLITE_OK ){
497 pWrapper->nData = (4096 + pWrapper->iSize);
498 pWrapper->zData = (char *)sqlite3_malloc(pWrapper->nData);
499 if( pWrapper->zData ){
500 memset(pWrapper->zData, 0, pWrapper->nData);
501 rc = sqlite3OsRead(pReal, pWrapper->zData, pWrapper->iSize, 0);
502 }else{
503 rc = SQLITE_NOMEM;
danielk197762079062007-08-15 17:08:46 +0000504 }
danielk1977f1da17a2007-08-21 13:07:46 +0000505 }
506 if( rc!=SQLITE_OK && pWrapper->pMethod ){
507 sqlite3OsClose(pFile);
danielk197762079062007-08-15 17:08:46 +0000508 }
509 return rc;
510}
511
danielk1977f1da17a2007-08-21 13:07:46 +0000512static int cfDelete(void *pAppData, const char *zPath, int dirSync){
513 sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
514 return pVfs->xDelete(pVfs->pAppData, zPath, dirSync);
515}
516static int cfAccess(void *pAppData, const char *zPath, int flags){
517 sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
518 return pVfs->xAccess(pVfs->pAppData, zPath, flags);
519}
520static int cfGetTempName(void *pAppData, char *zBufOut){
521 sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
522 return pVfs->xGetTempName(pVfs->pAppData, zBufOut);
523}
524static int cfFullPathname(void *pAppData, const char *zPath, char *zPathOut){
525 sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
526 return pVfs->xFullPathname(pVfs->pAppData, zPath, zPathOut);
527}
528static void *cfDlOpen(void *pAppData, const char *zPath){
529 sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
530 return pVfs->xDlOpen(pVfs->pAppData, zPath);
531}
532static int cfRandomness(void *pAppData, int nByte, char *zBufOut){
533 sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
534 return pVfs->xRandomness(pVfs->pAppData, nByte, zBufOut);
535}
536static int cfSleep(void *pAppData, int nMicro){
537 sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
538 return pVfs->xSleep(pVfs->pAppData, nMicro);
539}
540static int cfCurrentTime(void *pAppData, double *pTimeOut){
541 sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
542 return pVfs->xCurrentTime(pVfs->pAppData, pTimeOut);
543}
544
drh054889e2005-11-30 03:20:31 +0000545/*
danielk197762079062007-08-15 17:08:46 +0000546** tclcmd: sqlite_crashparams ?OPTIONS? DELAY CRASHFILE
drh9c06c952005-11-26 00:25:00 +0000547**
548** This procedure implements a TCL command that enables crash testing
549** in testfixture. Once enabled, crash testing cannot be disabled.
danielk197762079062007-08-15 17:08:46 +0000550**
551** Available options are "-characteristics" and "-sectorsize". Both require
552** an argument. For -sectorsize, this is the simulated sector size in
553** bytes. For -characteristics, the argument must be a list of io-capability
554** flags to simulate. Valid flags are "atomic", "atomic512", "atomic1K",
555** "atomic2K", "atomic4K", "atomic8K", "atomic16K", "atomic32K",
556** "atomic64K", "sequential" and "safe_append".
557**
558** Example:
559**
560** sqlite_crashparams -sect 1024 -char {atomic sequential} ./test.db 1
561**
drh9c06c952005-11-26 00:25:00 +0000562*/
563static int crashParamsObjCmd(
564 void * clientData,
565 Tcl_Interp *interp,
566 int objc,
567 Tcl_Obj *CONST objv[]
568){
danielk197762079062007-08-15 17:08:46 +0000569 int i;
danielk197762079062007-08-15 17:08:46 +0000570 int iDelay;
571 const char *zCrashFile;
572 int nCrashFile;
drhd677b3d2007-08-20 22:48:41 +0000573 static struct crashAppData appData;
574
danielk1977f1da17a2007-08-21 13:07:46 +0000575 static sqlite3_vfs crashVfs = {
576 1, /* iVersion */
577 0, /* szOsFile */
578 0, /* mxPathname */
579 0, /* nRef */
580 0, /* vfsMutex */
581 0, /* pNext */
582 "crash", /* zName */
583 0, /* pAppData */
584
585 cfOpen, /* xOpen */
586 cfDelete, /* xDelete */
587 cfAccess, /* xAccess */
588 cfGetTempName, /* xGetTempName */
589 cfFullPathname, /* xFullPathname */
590 cfDlOpen, /* xDlOpen */
591 0, /* xDlError */
592 0, /* xDlSym */
593 0, /* xDlClose */
594 cfRandomness, /* xRandomness */
595 cfSleep, /* xSleep */
596 cfCurrentTime /* xCurrentTime */
597 };
598
599 if( crashVfs.pAppData==0 ){
600 sqlite3_vfs *pOriginalVfs = sqlite3_vfs_find(0);
601 crashVfs.xDlError = pOriginalVfs->xDlError;
602 crashVfs.xDlSym = pOriginalVfs->xDlSym;
603 crashVfs.xDlClose = pOriginalVfs->xDlClose;
604 crashVfs.mxPathname = pOriginalVfs->mxPathname;
605 crashVfs.pAppData = (void *)pOriginalVfs;
606 crashVfs.szOsFile = sizeof(CrashFile) + pOriginalVfs->szOsFile;
drhd677b3d2007-08-20 22:48:41 +0000607 sqlite3_vfs_release(pOriginalVfs);
danielk1977f1da17a2007-08-21 13:07:46 +0000608 /* sqlite3_vfs_unregister(pOriginalVfs); */
drhd677b3d2007-08-20 22:48:41 +0000609 sqlite3_vfs_register(&crashVfs, 1);
610 }
danielk197762079062007-08-15 17:08:46 +0000611
612 int iDc = 0;
613 int iSectorSize = 0;
614 int setSectorsize = 0;
615 int setDeviceChar = 0;
616
617 struct DeviceFlag {
618 char *zName;
619 int iValue;
620 } aFlag[] = {
621 { "atomic", SQLITE_IOCAP_ATOMIC },
622 { "atomic512", SQLITE_IOCAP_ATOMIC512 },
623 { "atomic1k", SQLITE_IOCAP_ATOMIC1K },
624 { "atomic2k", SQLITE_IOCAP_ATOMIC2K },
625 { "atomic4k", SQLITE_IOCAP_ATOMIC4K },
626 { "atomic8k", SQLITE_IOCAP_ATOMIC8K },
627 { "atomic16k", SQLITE_IOCAP_ATOMIC16K },
628 { "atomic32k", SQLITE_IOCAP_ATOMIC32K },
629 { "atomic64k", SQLITE_IOCAP_ATOMIC64K },
630 { "sequential", SQLITE_IOCAP_SEQUENTIAL },
631 { "safe_append", SQLITE_IOCAP_SAFE_APPEND },
632 { 0, 0 }
633 };
634
635 if( objc<3 ){
636 Tcl_WrongNumArgs(interp, 1, objv, "?OPTIONS? DELAY CRASHFILE");
danielk1977b4b47412007-08-17 15:53:36 +0000637 goto error;
drh9c06c952005-11-26 00:25:00 +0000638 }
danielk197762079062007-08-15 17:08:46 +0000639
danielk1977967a4a12007-08-20 14:23:44 +0000640 zCrashFile = Tcl_GetStringFromObj(objv[objc-1], &nCrashFile);
danielk197762079062007-08-15 17:08:46 +0000641 if( nCrashFile>=sizeof(g.zCrashFile) ){
642 Tcl_AppendResult(interp, "Filename is too long: \"", zCrashFile, "\"", 0);
danielk1977b4b47412007-08-17 15:53:36 +0000643 goto error;
drh9c06c952005-11-26 00:25:00 +0000644 }
danielk197762079062007-08-15 17:08:46 +0000645 if( Tcl_GetIntFromObj(interp, objv[objc-2], &iDelay) ){
danielk1977b4b47412007-08-17 15:53:36 +0000646 goto error;
danielk197762079062007-08-15 17:08:46 +0000647 }
648
649 for(i=1; i<(objc-2); i+=2){
650 int nOpt;
651 char *zOpt = Tcl_GetStringFromObj(objv[i], &nOpt);
652
653 if( (nOpt>11 || nOpt<2 || strncmp("-sectorsize", zOpt, nOpt))
654 && (nOpt>16 || nOpt<2 || strncmp("-characteristics", zOpt, nOpt))
655 ){
656 Tcl_AppendResult(interp,
657 "Bad option: \"", zOpt,
658 "\" - must be \"-characteristics\" or \"-sectorsize\"", 0
659 );
danielk1977b4b47412007-08-17 15:53:36 +0000660 goto error;
danielk197759a33f92007-03-17 10:26:59 +0000661 }
danielk197762079062007-08-15 17:08:46 +0000662 if( i==objc-3 ){
663 Tcl_AppendResult(interp, "Option requires an argument: \"", zOpt, "\"",0);
danielk1977b4b47412007-08-17 15:53:36 +0000664 goto error;
danielk197762079062007-08-15 17:08:46 +0000665 }
666
667 if( zOpt[1]=='s' ){
668 if( Tcl_GetIntFromObj(interp, objv[i+1], &iSectorSize) ){
danielk1977b4b47412007-08-17 15:53:36 +0000669 goto error;
danielk197762079062007-08-15 17:08:46 +0000670 }
671 setSectorsize = 1;
672 }else{
673 int j;
674 Tcl_Obj **apObj;
675 int nObj;
676 if( Tcl_ListObjGetElements(interp, objv[i+1], &nObj, &apObj) ){
danielk1977b4b47412007-08-17 15:53:36 +0000677 goto error;
danielk197762079062007-08-15 17:08:46 +0000678 }
679 for(j=0; j<nObj; j++){
680 int rc;
681 int iChoice;
682 Tcl_Obj *pFlag = Tcl_DuplicateObj(apObj[j]);
683 Tcl_IncrRefCount(pFlag);
684 Tcl_UtfToLower(Tcl_GetString(pFlag));
685
686 rc = Tcl_GetIndexFromObjStruct(
687 interp, pFlag, aFlag, sizeof(aFlag[0]), "no such flag", 0, &iChoice
688 );
689 Tcl_DecrRefCount(pFlag);
690 if( rc ){
danielk1977b4b47412007-08-17 15:53:36 +0000691 goto error;
danielk197762079062007-08-15 17:08:46 +0000692 }
693
694 iDc |= aFlag[iChoice].iValue;
695 }
696 setDeviceChar = 1;
697 }
danielk197759a33f92007-03-17 10:26:59 +0000698 }
danielk197762079062007-08-15 17:08:46 +0000699
700 if( setDeviceChar ){
701 g.iDeviceCharacteristics = iDc;
702 }
703 if( setSectorsize ){
704 g.iSectorSize = iSectorSize;
705 }
706 g.iCrash = iDelay;
707 memcpy(g.zCrashFile, zCrashFile, nCrashFile+1);
drh66560ad2006-01-06 14:32:19 +0000708 sqlite3CrashTestEnable = 1;
drh9c06c952005-11-26 00:25:00 +0000709 return TCL_OK;
danielk1977b4b47412007-08-17 15:53:36 +0000710
711error:
danielk1977b4b47412007-08-17 15:53:36 +0000712 return TCL_ERROR;
drh9c06c952005-11-26 00:25:00 +0000713}
714
drh198bf392006-01-06 21:52:49 +0000715#endif /* SQLITE_OMIT_DISKIO */
716
drh9c06c952005-11-26 00:25:00 +0000717/*
718** This procedure registers the TCL procedures defined in this file.
719*/
720int Sqlitetest6_Init(Tcl_Interp *interp){
drh198bf392006-01-06 21:52:49 +0000721#ifndef SQLITE_OMIT_DISKIO
drh9c06c952005-11-26 00:25:00 +0000722 Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0);
drh198bf392006-01-06 21:52:49 +0000723#endif
drh9c06c952005-11-26 00:25:00 +0000724 return TCL_OK;
725}
726
727#endif /* SQLITE_TEST */