persistentstorage/sqlite3api/TEST/SRC/test6.c
changeset 0 08ec8eefde2f
child 23 26645d81f48d
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 /*
       
     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 ** $Id: test6.c,v 1.39 2008/06/06 11:11:26 danielk1977 Exp $
       
    18 */
       
    19 #if SQLITE_TEST          /* This file is used for testing only */
       
    20 #include "sqliteInt.h"
       
    21 #include "tcl.h"
       
    22 
       
    23 #ifndef SQLITE_OMIT_DISKIO  /* This file is a no-op if disk I/O is disabled */
       
    24 
       
    25 /* #define TRACE_CRASHTEST */
       
    26 
       
    27 typedef struct CrashFile CrashFile;
       
    28 typedef struct CrashGlobal CrashGlobal;
       
    29 typedef struct WriteBuffer WriteBuffer;
       
    30 
       
    31 /*
       
    32 ** Method:
       
    33 **
       
    34 **   This layer is implemented as a wrapper around the "real" 
       
    35 **   sqlite3_file object for the host system. Each time data is 
       
    36 **   written to the file object, instead of being written to the
       
    37 **   underlying file, the write operation is stored in an in-memory 
       
    38 **   structure (type WriteBuffer). This structure is placed at the
       
    39 **   end of a global ordered list (the write-list).
       
    40 **
       
    41 **   When data is read from a file object, the requested region is
       
    42 **   first retrieved from the real file. The write-list is then 
       
    43 **   traversed and data copied from any overlapping WriteBuffer 
       
    44 **   structures to the output buffer. i.e. a read() operation following
       
    45 **   one or more write() operations works as expected, even if no
       
    46 **   data has actually been written out to the real file.
       
    47 **
       
    48 **   When a fsync() operation is performed, an operating system crash 
       
    49 **   may be simulated, in which case exit(-1) is called (the call to 
       
    50 **   xSync() never returns). Whether or not a crash is simulated,
       
    51 **   the data associated with a subset of the WriteBuffer structures 
       
    52 **   stored in the write-list is written to the real underlying files 
       
    53 **   and the entries removed from the write-list. If a crash is simulated,
       
    54 **   a subset of the buffers may be corrupted before the data is written.
       
    55 **
       
    56 **   The exact subset of the write-list written and/or corrupted is
       
    57 **   determined by the simulated device characteristics and sector-size.
       
    58 **
       
    59 ** "Normal" mode:
       
    60 **
       
    61 **   Normal mode is used when the simulated device has none of the
       
    62 **   SQLITE_IOCAP_XXX flags set.
       
    63 **
       
    64 **   In normal mode, if the fsync() is not a simulated crash, the 
       
    65 **   write-list is traversed from beginning to end. Each WriteBuffer
       
    66 **   structure associated with the file handle used to call xSync()
       
    67 **   is written to the real file and removed from the write-list.
       
    68 **
       
    69 **   If a crash is simulated, one of the following takes place for 
       
    70 **   each WriteBuffer in the write-list, regardless of which 
       
    71 **   file-handle it is associated with:
       
    72 **
       
    73 **     1. The buffer is correctly written to the file, just as if
       
    74 **        a crash were not being simulated.
       
    75 **
       
    76 **     2. Nothing is done.
       
    77 **
       
    78 **     3. Garbage data is written to all sectors of the file that 
       
    79 **        overlap the region specified by the WriteBuffer. Or garbage
       
    80 **        data is written to some contiguous section within the 
       
    81 **        overlapped sectors.
       
    82 **
       
    83 ** Device Characteristic flag handling:
       
    84 **
       
    85 **   If the IOCAP_ATOMIC flag is set, then option (3) above is 
       
    86 **   never selected.
       
    87 **
       
    88 **   If the IOCAP_ATOMIC512 flag is set, and the WriteBuffer represents
       
    89 **   an aligned write() of an integer number of 512 byte regions, then
       
    90 **   option (3) above is never selected. Instead, each 512 byte region
       
    91 **   is either correctly written or left completely untouched. Similar
       
    92 **   logic governs the behaviour if any of the other ATOMICXXX flags
       
    93 **   is set.
       
    94 **
       
    95 **   If either the IOCAP_SAFEAPPEND or IOCAP_SEQUENTIAL flags are set
       
    96 **   and a crash is being simulated, then an entry of the write-list is
       
    97 **   selected at random. Everything in the list after the selected entry 
       
    98 **   is discarded before processing begins.
       
    99 **
       
   100 **   If IOCAP_SEQUENTIAL is set and a crash is being simulated, option 
       
   101 **   (1) is selected for all write-list entries except the last. If a 
       
   102 **   crash is not being simulated, then all entries in the write-list
       
   103 **   that occur before at least one write() on the file-handle specified
       
   104 **   as part of the xSync() are written to their associated real files.
       
   105 **
       
   106 **   If IOCAP_SAFEAPPEND is set and the first byte written by the write()
       
   107 **   operation is one byte past the current end of the file, then option
       
   108 **   (1) is always selected.
       
   109 */
       
   110 
       
   111 /*
       
   112 ** Each write operation in the write-list is represented by an instance
       
   113 ** of the following structure.
       
   114 **
       
   115 ** If zBuf is 0, then this structure represents a call to xTruncate(), 
       
   116 ** not xWrite(). In that case, iOffset is the size that the file is
       
   117 ** truncated to.
       
   118 */
       
   119 struct WriteBuffer {
       
   120   i64 iOffset;                 /* Byte offset of the start of this write() */
       
   121   int nBuf;                    /* Number of bytes written */
       
   122   u8 *zBuf;                    /* Pointer to copy of written data */
       
   123   CrashFile *pFile;            /* File this write() applies to */
       
   124 
       
   125   WriteBuffer *pNext;          /* Next in CrashGlobal.pWriteList */
       
   126 };
       
   127 
       
   128 struct CrashFile {
       
   129   const sqlite3_io_methods *pMethod;   /* Must be first */
       
   130   sqlite3_file *pRealFile;             /* Underlying "real" file handle */
       
   131   char *zName;
       
   132 
       
   133   /* Cache of the entire file. This is used to speed up OsRead() and 
       
   134   ** OsFileSize() calls. Although both could be done by traversing the
       
   135   ** write-list, in practice this is impractically slow.
       
   136   */
       
   137   int iSize;                           /* Size of file in bytes */
       
   138   int nData;                           /* Size of buffer allocated at zData */
       
   139   u8 *zData;                           /* Buffer containing file contents */
       
   140 };
       
   141 
       
   142 struct CrashGlobal {
       
   143   WriteBuffer *pWriteList;     /* Head of write-list */
       
   144   WriteBuffer *pWriteListEnd;  /* End of write-list */
       
   145 
       
   146   int iSectorSize;             /* Value of simulated sector size */
       
   147   int iDeviceCharacteristics;  /* Value of simulated device characteristics */
       
   148 
       
   149   int iCrash;                  /* Crash on the iCrash'th call to xSync() */
       
   150   char zCrashFile[500];        /* Crash during an xSync() on this file */ 
       
   151 };
       
   152 
       
   153 static CrashGlobal g = {0, 0, SQLITE_DEFAULT_SECTOR_SIZE, 0, 0};
       
   154 
       
   155 /*
       
   156 ** Set this global variable to 1 to enable crash testing.
       
   157 */
       
   158 static int sqlite3CrashTestEnable = 0;
       
   159 
       
   160 static void *crash_malloc(int nByte){
       
   161   return (void *)Tcl_Alloc((size_t)nByte);
       
   162 }
       
   163 static void crash_free(void *p){
       
   164   Tcl_Free(p);
       
   165 }
       
   166 static void *crash_realloc(void *p, int n){
       
   167   return (void *)Tcl_Realloc(p, (size_t)n);
       
   168 }
       
   169 
       
   170 /*
       
   171 ** Flush the write-list as if xSync() had been called on file handle
       
   172 ** pFile. If isCrash is true, simulate a crash.
       
   173 */
       
   174 static int writeListSync(CrashFile *pFile, int isCrash){
       
   175   int rc = SQLITE_OK;
       
   176   int iDc = g.iDeviceCharacteristics;
       
   177 
       
   178   WriteBuffer *pWrite;
       
   179   WriteBuffer **ppPtr;
       
   180 
       
   181   /* If this is not a crash simulation, set pFinal to point to the 
       
   182   ** last element of the write-list that is associated with file handle
       
   183   ** pFile.
       
   184   **
       
   185   ** If this is a crash simulation, set pFinal to an arbitrarily selected
       
   186   ** element of the write-list.
       
   187   */
       
   188   WriteBuffer *pFinal = 0;
       
   189   if( !isCrash ){
       
   190     for(pWrite=g.pWriteList; pWrite; pWrite=pWrite->pNext){
       
   191       if( pWrite->pFile==pFile ){
       
   192         pFinal = pWrite;
       
   193       }
       
   194     }
       
   195   }else if( iDc&(SQLITE_IOCAP_SEQUENTIAL|SQLITE_IOCAP_SAFE_APPEND) ){
       
   196     int nWrite = 0;
       
   197     int iFinal;
       
   198     for(pWrite=g.pWriteList; pWrite; pWrite=pWrite->pNext) nWrite++;
       
   199     sqlite3_randomness(sizeof(int), &iFinal);
       
   200     iFinal = ((iFinal<0)?-1*iFinal:iFinal)%nWrite;
       
   201     for(pWrite=g.pWriteList; iFinal>0; pWrite=pWrite->pNext) iFinal--;
       
   202     pFinal = pWrite;
       
   203   }
       
   204 
       
   205 #ifdef TRACE_CRASHTEST
       
   206   printf("Sync %s (is %s crash)\n", pFile->zName, (isCrash?"a":"not a"));
       
   207 #endif
       
   208 
       
   209   ppPtr = &g.pWriteList;
       
   210   for(pWrite=*ppPtr; rc==SQLITE_OK && pWrite; pWrite=*ppPtr){
       
   211     sqlite3_file *pRealFile = pWrite->pFile->pRealFile;
       
   212 
       
   213     /* (eAction==1)      -> write block out normally,
       
   214     ** (eAction==2)      -> do nothing,
       
   215     ** (eAction==3)      -> trash sectors.
       
   216     */
       
   217     int eAction = 0;
       
   218     if( !isCrash ){
       
   219       eAction = 2;
       
   220       if( (pWrite->pFile==pFile || iDc&SQLITE_IOCAP_SEQUENTIAL) ){
       
   221         eAction = 1;
       
   222       }
       
   223     }else{
       
   224       char random;
       
   225       sqlite3_randomness(1, &random);
       
   226 
       
   227       /* Do not select option 3 (sector trashing) if the IOCAP_ATOMIC flag 
       
   228       ** is set or this is an OsTruncate(), not an Oswrite().
       
   229       */
       
   230       if( (iDc&SQLITE_IOCAP_ATOMIC) || (pWrite->zBuf==0) ){
       
   231         random &= 0x01;
       
   232       }
       
   233 
       
   234       /* If IOCAP_SEQUENTIAL is set and this is not the final entry
       
   235       ** in the truncated write-list, always select option 1 (write
       
   236       ** out correctly).
       
   237       */
       
   238       if( (iDc&SQLITE_IOCAP_SEQUENTIAL && pWrite!=pFinal) ){
       
   239         random = 0;
       
   240       }
       
   241 
       
   242       /* If IOCAP_SAFE_APPEND is set and this OsWrite() operation is
       
   243       ** an append (first byte of the written region is 1 byte past the
       
   244       ** current EOF), always select option 1 (write out correctly).
       
   245       */
       
   246       if( iDc&SQLITE_IOCAP_SAFE_APPEND && pWrite->zBuf ){
       
   247         i64 iSize;
       
   248         sqlite3OsFileSize(pRealFile, &iSize);
       
   249         if( iSize==pWrite->iOffset ){
       
   250           random = 0;
       
   251         }
       
   252       }
       
   253 
       
   254       if( (random&0x06)==0x06 ){
       
   255         eAction = 3;
       
   256       }else{
       
   257         eAction = ((random&0x01)?2:1);
       
   258       }
       
   259     }
       
   260 
       
   261     switch( eAction ){
       
   262       case 1: {               /* Write out correctly */
       
   263         if( pWrite->zBuf ){
       
   264           rc = sqlite3OsWrite(
       
   265               pRealFile, pWrite->zBuf, pWrite->nBuf, pWrite->iOffset
       
   266           );
       
   267         }else{
       
   268           rc = sqlite3OsTruncate(pRealFile, pWrite->iOffset);
       
   269         }
       
   270         *ppPtr = pWrite->pNext;
       
   271 #ifdef TRACE_CRASHTEST
       
   272         if( isCrash ){
       
   273           printf("Writing %d bytes @ %d (%s)\n", 
       
   274             pWrite->nBuf, (int)pWrite->iOffset, pWrite->pFile->zName
       
   275           );
       
   276         }
       
   277 #endif
       
   278         crash_free(pWrite);
       
   279         break;
       
   280       }
       
   281       case 2: {               /* Do nothing */
       
   282         ppPtr = &pWrite->pNext;
       
   283 #ifdef TRACE_CRASHTEST
       
   284         if( isCrash ){
       
   285           printf("Omiting %d bytes @ %d (%s)\n", 
       
   286             pWrite->nBuf, (int)pWrite->iOffset, pWrite->pFile->zName
       
   287           );
       
   288         }
       
   289 #endif
       
   290         break;
       
   291       }
       
   292       case 3: {               /* Trash sectors */
       
   293         u8 *zGarbage;
       
   294         int iFirst = (pWrite->iOffset/g.iSectorSize);
       
   295         int iLast = (pWrite->iOffset+pWrite->nBuf-1)/g.iSectorSize;
       
   296 
       
   297         assert(pWrite->zBuf);
       
   298 
       
   299 #ifdef TRACE_CRASHTEST
       
   300         printf("Trashing %d sectors @ sector %d (%s)\n", 
       
   301             1+iLast-iFirst, iFirst, pWrite->pFile->zName
       
   302         );
       
   303 #endif
       
   304 
       
   305         zGarbage = crash_malloc(g.iSectorSize);
       
   306         if( zGarbage ){
       
   307           sqlite3_int64 i;
       
   308           for(i=iFirst; rc==SQLITE_OK && i<=iLast; i++){
       
   309             sqlite3_randomness(g.iSectorSize, zGarbage); 
       
   310             rc = sqlite3OsWrite(
       
   311               pRealFile, zGarbage, g.iSectorSize, i*g.iSectorSize
       
   312             );
       
   313           }
       
   314           crash_free(zGarbage);
       
   315         }else{
       
   316           rc = SQLITE_NOMEM;
       
   317         }
       
   318 
       
   319         ppPtr = &pWrite->pNext;
       
   320         break;
       
   321       }
       
   322 
       
   323       default:
       
   324         assert(!"Cannot happen");
       
   325     }
       
   326 
       
   327     if( pWrite==pFinal ) break;
       
   328   }
       
   329 
       
   330   if( rc==SQLITE_OK && isCrash ){
       
   331     exit(-1);
       
   332   }
       
   333 
       
   334   for(pWrite=g.pWriteList; pWrite && pWrite->pNext; pWrite=pWrite->pNext);
       
   335   g.pWriteListEnd = pWrite;
       
   336 
       
   337   return rc;
       
   338 }
       
   339 
       
   340 /*
       
   341 ** Add an entry to the end of the write-list.
       
   342 */
       
   343 static int writeListAppend(
       
   344   sqlite3_file *pFile,
       
   345   sqlite3_int64 iOffset,
       
   346   const u8 *zBuf,
       
   347   int nBuf
       
   348 ){
       
   349   WriteBuffer *pNew;
       
   350 
       
   351   assert((zBuf && nBuf) || (!nBuf && !zBuf));
       
   352 
       
   353   pNew = (WriteBuffer *)crash_malloc(sizeof(WriteBuffer) + nBuf);
       
   354   if( pNew==0 ){
       
   355     fprintf(stderr, "out of memory in the crash simulator\n");
       
   356   }
       
   357   memset(pNew, 0, sizeof(WriteBuffer)+nBuf);
       
   358   pNew->iOffset = iOffset;
       
   359   pNew->nBuf = nBuf;
       
   360   pNew->pFile = (CrashFile *)pFile;
       
   361   if( zBuf ){
       
   362     pNew->zBuf = (u8 *)&pNew[1];
       
   363     memcpy(pNew->zBuf, zBuf, nBuf);
       
   364   }
       
   365 
       
   366   if( g.pWriteList ){
       
   367     assert(g.pWriteListEnd);
       
   368     g.pWriteListEnd->pNext = pNew;
       
   369   }else{
       
   370     g.pWriteList = pNew;
       
   371   }
       
   372   g.pWriteListEnd = pNew;
       
   373   
       
   374   return SQLITE_OK;
       
   375 }
       
   376 
       
   377 /*
       
   378 ** Close a crash-file.
       
   379 */
       
   380 static int cfClose(sqlite3_file *pFile){
       
   381   CrashFile *pCrash = (CrashFile *)pFile;
       
   382   writeListSync(pCrash, 0);
       
   383   sqlite3OsClose(pCrash->pRealFile);
       
   384   return SQLITE_OK;
       
   385 }
       
   386 
       
   387 /*
       
   388 ** Read data from a crash-file.
       
   389 */
       
   390 static int cfRead(
       
   391   sqlite3_file *pFile, 
       
   392   void *zBuf, 
       
   393   int iAmt, 
       
   394   sqlite_int64 iOfst
       
   395 ){
       
   396   CrashFile *pCrash = (CrashFile *)pFile;
       
   397 
       
   398   /* Check the file-size to see if this is a short-read */
       
   399   if( pCrash->iSize<(iOfst+iAmt) ){
       
   400     return SQLITE_IOERR_SHORT_READ;
       
   401   }
       
   402 
       
   403   memcpy(zBuf, &pCrash->zData[iOfst], iAmt);
       
   404   return SQLITE_OK;
       
   405 }
       
   406 
       
   407 /*
       
   408 ** Write data to a crash-file.
       
   409 */
       
   410 static int cfWrite(
       
   411   sqlite3_file *pFile, 
       
   412   const void *zBuf, 
       
   413   int iAmt, 
       
   414   sqlite_int64 iOfst
       
   415 ){
       
   416   CrashFile *pCrash = (CrashFile *)pFile;
       
   417   if( iAmt+iOfst>pCrash->iSize ){
       
   418     pCrash->iSize = iAmt+iOfst;
       
   419   }
       
   420   while( pCrash->iSize>pCrash->nData ){
       
   421     u8 *zNew;
       
   422     int nNew = (pCrash->nData*2) + 4096;
       
   423     zNew = crash_realloc(pCrash->zData, nNew);
       
   424     if( !zNew ){
       
   425       return SQLITE_NOMEM;
       
   426     }
       
   427     memset(&zNew[pCrash->nData], 0, nNew-pCrash->nData);
       
   428     pCrash->nData = nNew;
       
   429     pCrash->zData = zNew;
       
   430   }
       
   431   memcpy(&pCrash->zData[iOfst], zBuf, iAmt);
       
   432   return writeListAppend(pFile, iOfst, zBuf, iAmt);
       
   433 }
       
   434 
       
   435 /*
       
   436 ** Truncate a crash-file.
       
   437 */
       
   438 static int cfTruncate(sqlite3_file *pFile, sqlite_int64 size){
       
   439   CrashFile *pCrash = (CrashFile *)pFile;
       
   440   assert(size>=0);
       
   441   if( pCrash->iSize>size ){
       
   442     pCrash->iSize = size;
       
   443   }
       
   444   return writeListAppend(pFile, size, 0, 0);
       
   445 }
       
   446 
       
   447 /*
       
   448 ** Sync a crash-file.
       
   449 */
       
   450 static int cfSync(sqlite3_file *pFile, int flags){
       
   451   CrashFile *pCrash = (CrashFile *)pFile;
       
   452   int isCrash = 0;
       
   453 
       
   454   const char *zName = pCrash->zName;
       
   455   const char *zCrashFile = g.zCrashFile;
       
   456   int nName = strlen(zName);
       
   457   int nCrashFile = strlen(zCrashFile);
       
   458 
       
   459   if( nCrashFile>0 && zCrashFile[nCrashFile-1]=='*' ){
       
   460     nCrashFile--;
       
   461     if( nName>nCrashFile ) nName = nCrashFile;
       
   462   }
       
   463 
       
   464   if( nName==nCrashFile && 0==memcmp(zName, zCrashFile, nName) ){
       
   465     if( (--g.iCrash)==0 ) isCrash = 1;
       
   466   }
       
   467 
       
   468   return writeListSync(pCrash, isCrash);
       
   469 }
       
   470 
       
   471 /*
       
   472 ** Return the current file-size of the crash-file.
       
   473 */
       
   474 static int cfFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
       
   475   CrashFile *pCrash = (CrashFile *)pFile;
       
   476   *pSize = (i64)pCrash->iSize;
       
   477   return SQLITE_OK;
       
   478 }
       
   479 
       
   480 /*
       
   481 ** Calls related to file-locks are passed on to the real file handle.
       
   482 */
       
   483 static int cfLock(sqlite3_file *pFile, int eLock){
       
   484   return sqlite3OsLock(((CrashFile *)pFile)->pRealFile, eLock);
       
   485 }
       
   486 static int cfUnlock(sqlite3_file *pFile, int eLock){
       
   487   return sqlite3OsUnlock(((CrashFile *)pFile)->pRealFile, eLock);
       
   488 }
       
   489 static int cfCheckReservedLock(sqlite3_file *pFile, int *pResOut){
       
   490   return sqlite3OsCheckReservedLock(((CrashFile *)pFile)->pRealFile, pResOut);
       
   491 }
       
   492 static int cfFileControl(sqlite3_file *pFile, int op, void *pArg){
       
   493   return sqlite3OsFileControl(((CrashFile *)pFile)->pRealFile, op, pArg);
       
   494 }
       
   495 
       
   496 /*
       
   497 ** The xSectorSize() and xDeviceCharacteristics() functions return
       
   498 ** the global values configured by the [sqlite_crashparams] tcl
       
   499 *  interface.
       
   500 */
       
   501 static int cfSectorSize(sqlite3_file *pFile){
       
   502   return g.iSectorSize;
       
   503 }
       
   504 static int cfDeviceCharacteristics(sqlite3_file *pFile){
       
   505   return g.iDeviceCharacteristics;
       
   506 }
       
   507 
       
   508 static const sqlite3_io_methods CrashFileVtab = {
       
   509   1,                            /* iVersion */
       
   510   cfClose,                      /* xClose */
       
   511   cfRead,                       /* xRead */
       
   512   cfWrite,                      /* xWrite */
       
   513   cfTruncate,                   /* xTruncate */
       
   514   cfSync,                       /* xSync */
       
   515   cfFileSize,                   /* xFileSize */
       
   516   cfLock,                       /* xLock */
       
   517   cfUnlock,                     /* xUnlock */
       
   518   cfCheckReservedLock,          /* xCheckReservedLock */
       
   519   cfFileControl,                /* xFileControl */
       
   520   cfSectorSize,                 /* xSectorSize */
       
   521   cfDeviceCharacteristics       /* xDeviceCharacteristics */
       
   522 };
       
   523 
       
   524 /*
       
   525 ** Application data for the crash VFS
       
   526 */
       
   527 struct crashAppData {
       
   528   sqlite3_vfs *pOrig;                   /* Wrapped vfs structure */
       
   529 };
       
   530 
       
   531 /*
       
   532 ** Open a crash-file file handle.
       
   533 **
       
   534 ** The caller will have allocated pVfs->szOsFile bytes of space
       
   535 ** at pFile. This file uses this space for the CrashFile structure
       
   536 ** and allocates space for the "real" file structure using 
       
   537 ** sqlite3_malloc(). The assumption here is (pVfs->szOsFile) is
       
   538 ** equal or greater than sizeof(CrashFile).
       
   539 */
       
   540 static int cfOpen(
       
   541   sqlite3_vfs *pCfVfs,
       
   542   const char *zName,
       
   543   sqlite3_file *pFile,
       
   544   int flags,
       
   545   int *pOutFlags
       
   546 ){
       
   547   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
       
   548   int rc;
       
   549   CrashFile *pWrapper = (CrashFile *)pFile;
       
   550   sqlite3_file *pReal = (sqlite3_file*)&pWrapper[1];
       
   551 
       
   552   memset(pWrapper, 0, sizeof(CrashFile));
       
   553   rc = sqlite3OsOpen(pVfs, zName, pReal, flags, pOutFlags);
       
   554 
       
   555   if( rc==SQLITE_OK ){
       
   556     i64 iSize;
       
   557     pWrapper->pMethod = &CrashFileVtab;
       
   558     pWrapper->zName = (char *)zName;
       
   559     pWrapper->pRealFile = pReal;
       
   560     rc = sqlite3OsFileSize(pReal, &iSize);
       
   561     pWrapper->iSize = (int)iSize;
       
   562   }
       
   563   if( rc==SQLITE_OK ){
       
   564     pWrapper->nData = (4096 + pWrapper->iSize);
       
   565     pWrapper->zData = crash_malloc(pWrapper->nData);
       
   566     if( pWrapper->zData ){
       
   567       memset(pWrapper->zData, 0, pWrapper->nData);
       
   568       rc = sqlite3OsRead(pReal, pWrapper->zData, pWrapper->iSize, 0); 
       
   569     }else{
       
   570       rc = SQLITE_NOMEM;
       
   571     }
       
   572   }
       
   573   if( rc!=SQLITE_OK && pWrapper->pMethod ){
       
   574     sqlite3OsClose(pFile);
       
   575   }
       
   576   return rc;
       
   577 }
       
   578 
       
   579 static int cfDelete(sqlite3_vfs *pCfVfs, const char *zPath, int dirSync){
       
   580   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
       
   581   return pVfs->xDelete(pVfs, zPath, dirSync);
       
   582 }
       
   583 static int cfAccess(
       
   584   sqlite3_vfs *pCfVfs, 
       
   585   const char *zPath, 
       
   586   int flags, 
       
   587   int *pResOut
       
   588 ){
       
   589   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
       
   590   return pVfs->xAccess(pVfs, zPath, flags, pResOut);
       
   591 }
       
   592 static int cfFullPathname(
       
   593   sqlite3_vfs *pCfVfs, 
       
   594   const char *zPath, 
       
   595   int nPathOut,
       
   596   char *zPathOut
       
   597 ){
       
   598   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
       
   599   return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut);
       
   600 }
       
   601 static void *cfDlOpen(sqlite3_vfs *pCfVfs, const char *zPath){
       
   602   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
       
   603   return pVfs->xDlOpen(pVfs, zPath);
       
   604 }
       
   605 static void cfDlError(sqlite3_vfs *pCfVfs, int nByte, char *zErrMsg){
       
   606   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
       
   607   pVfs->xDlError(pVfs, nByte, zErrMsg);
       
   608 }
       
   609 static void *cfDlSym(sqlite3_vfs *pCfVfs, void *pHandle, const char *zSymbol){
       
   610   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
       
   611   return pVfs->xDlSym(pVfs, pHandle, zSymbol);
       
   612 }
       
   613 static void cfDlClose(sqlite3_vfs *pCfVfs, void *pHandle){
       
   614   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
       
   615   pVfs->xDlClose(pVfs, pHandle);
       
   616 }
       
   617 static int cfRandomness(sqlite3_vfs *pCfVfs, int nByte, char *zBufOut){
       
   618   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
       
   619   return pVfs->xRandomness(pVfs, nByte, zBufOut);
       
   620 }
       
   621 static int cfSleep(sqlite3_vfs *pCfVfs, int nMicro){
       
   622   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
       
   623   return pVfs->xSleep(pVfs, nMicro);
       
   624 }
       
   625 static int cfCurrentTime(sqlite3_vfs *pCfVfs, double *pTimeOut){
       
   626   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
       
   627   return pVfs->xCurrentTime(pVfs, pTimeOut);
       
   628 }
       
   629 
       
   630 static int processDevSymArgs(
       
   631   Tcl_Interp *interp,
       
   632   int objc,
       
   633   Tcl_Obj *CONST objv[],
       
   634   int *piDeviceChar,
       
   635   int *piSectorSize
       
   636 ){
       
   637   struct DeviceFlag {
       
   638     char *zName;
       
   639     int iValue;
       
   640   } aFlag[] = {
       
   641     { "atomic",      SQLITE_IOCAP_ATOMIC      },
       
   642     { "atomic512",   SQLITE_IOCAP_ATOMIC512   },
       
   643     { "atomic1k",    SQLITE_IOCAP_ATOMIC1K    },
       
   644     { "atomic2k",    SQLITE_IOCAP_ATOMIC2K    },
       
   645     { "atomic4k",    SQLITE_IOCAP_ATOMIC4K    },
       
   646     { "atomic8k",    SQLITE_IOCAP_ATOMIC8K    },
       
   647     { "atomic16k",   SQLITE_IOCAP_ATOMIC16K   },
       
   648     { "atomic32k",   SQLITE_IOCAP_ATOMIC32K   },
       
   649     { "atomic64k",   SQLITE_IOCAP_ATOMIC64K   },
       
   650     { "sequential",  SQLITE_IOCAP_SEQUENTIAL  },
       
   651     { "safe_append", SQLITE_IOCAP_SAFE_APPEND },
       
   652     { 0, 0 }
       
   653   };
       
   654 
       
   655   int i;
       
   656   int iDc = 0;
       
   657   int iSectorSize = 0;
       
   658   int setSectorsize = 0;
       
   659   int setDeviceChar = 0;
       
   660 
       
   661   for(i=0; i<objc; i+=2){
       
   662     int nOpt;
       
   663     char *zOpt = Tcl_GetStringFromObj(objv[i], &nOpt);
       
   664 
       
   665     if( (nOpt>11 || nOpt<2 || strncmp("-sectorsize", zOpt, nOpt)) 
       
   666      && (nOpt>16 || nOpt<2 || strncmp("-characteristics", zOpt, nOpt))
       
   667     ){
       
   668       Tcl_AppendResult(interp, 
       
   669         "Bad option: \"", zOpt, 
       
   670         "\" - must be \"-characteristics\" or \"-sectorsize\"", 0
       
   671       );
       
   672       return TCL_ERROR;
       
   673     }
       
   674     if( i==objc-1 ){
       
   675       Tcl_AppendResult(interp, "Option requires an argument: \"", zOpt, "\"",0);
       
   676       return TCL_ERROR;
       
   677     }
       
   678 
       
   679     if( zOpt[1]=='s' ){
       
   680       if( Tcl_GetIntFromObj(interp, objv[i+1], &iSectorSize) ){
       
   681         return TCL_ERROR;
       
   682       }
       
   683       setSectorsize = 1;
       
   684     }else{
       
   685       int j;
       
   686       Tcl_Obj **apObj;
       
   687       int nObj;
       
   688       if( Tcl_ListObjGetElements(interp, objv[i+1], &nObj, &apObj) ){
       
   689         return TCL_ERROR;
       
   690       }
       
   691       for(j=0; j<nObj; j++){
       
   692         int rc;
       
   693         int iChoice;
       
   694         Tcl_Obj *pFlag = Tcl_DuplicateObj(apObj[j]);
       
   695         Tcl_IncrRefCount(pFlag);
       
   696         Tcl_UtfToLower(Tcl_GetString(pFlag));
       
   697  
       
   698         rc = Tcl_GetIndexFromObjStruct(
       
   699             interp, pFlag, aFlag, sizeof(aFlag[0]), "no such flag", 0, &iChoice
       
   700         );
       
   701         Tcl_DecrRefCount(pFlag);
       
   702         if( rc ){
       
   703           return TCL_ERROR;
       
   704         }
       
   705 
       
   706         iDc |= aFlag[iChoice].iValue;
       
   707       }
       
   708       setDeviceChar = 1;
       
   709     }
       
   710   }
       
   711 
       
   712   if( setDeviceChar ){
       
   713     *piDeviceChar = iDc;
       
   714   }
       
   715   if( setSectorsize ){
       
   716     *piSectorSize = iSectorSize;
       
   717   }
       
   718 
       
   719   return TCL_OK;
       
   720 }
       
   721 
       
   722 /*
       
   723 ** tclcmd:   sqlite_crash_enable ENABLE
       
   724 **
       
   725 ** Parameter ENABLE must be a boolean value. If true, then the "crash"
       
   726 ** vfs is added to the system. If false, it is removed.
       
   727 */
       
   728 static int crashEnableCmd(
       
   729   void * clientData,
       
   730   Tcl_Interp *interp,
       
   731   int objc,
       
   732   Tcl_Obj *CONST objv[]
       
   733 ){
       
   734   int isEnable;
       
   735   static sqlite3_vfs crashVfs = {
       
   736     1,                  /* iVersion */
       
   737     0,                  /* szOsFile */
       
   738     0,                  /* mxPathname */
       
   739     0,                  /* pNext */
       
   740     "crash",            /* zName */
       
   741     0,                  /* pAppData */
       
   742   
       
   743     cfOpen,               /* xOpen */
       
   744     cfDelete,             /* xDelete */
       
   745     cfAccess,             /* xAccess */
       
   746     cfFullPathname,       /* xFullPathname */
       
   747     cfDlOpen,             /* xDlOpen */
       
   748     cfDlError,            /* xDlError */
       
   749     cfDlSym,              /* xDlSym */
       
   750     cfDlClose,            /* xDlClose */
       
   751     cfRandomness,         /* xRandomness */
       
   752     cfSleep,              /* xSleep */
       
   753     cfCurrentTime         /* xCurrentTime */
       
   754   };
       
   755 
       
   756   if( objc!=2 ){
       
   757     Tcl_WrongNumArgs(interp, 1, objv, "ENABLE");
       
   758     return TCL_ERROR;
       
   759   }
       
   760 
       
   761   if( Tcl_GetBooleanFromObj(interp, objv[1], &isEnable) ){
       
   762     return TCL_ERROR;
       
   763   }
       
   764 
       
   765   if( (isEnable && crashVfs.pAppData) || (!isEnable && !crashVfs.pAppData) ){
       
   766     return TCL_OK;
       
   767   }
       
   768 
       
   769   if( crashVfs.pAppData==0 ){
       
   770     sqlite3_vfs *pOriginalVfs = sqlite3_vfs_find(0);
       
   771     crashVfs.mxPathname = pOriginalVfs->mxPathname;
       
   772     crashVfs.pAppData = (void *)pOriginalVfs;
       
   773     crashVfs.szOsFile = sizeof(CrashFile) + pOriginalVfs->szOsFile;
       
   774     sqlite3_vfs_register(&crashVfs, 0);
       
   775   }else{
       
   776     crashVfs.pAppData = 0;
       
   777     sqlite3_vfs_unregister(&crashVfs);
       
   778   }
       
   779 
       
   780   return TCL_OK;
       
   781 }
       
   782 
       
   783 /*
       
   784 ** tclcmd:   sqlite_crashparams ?OPTIONS? DELAY CRASHFILE
       
   785 **
       
   786 ** This procedure implements a TCL command that enables crash testing
       
   787 ** in testfixture.  Once enabled, crash testing cannot be disabled.
       
   788 **
       
   789 ** Available options are "-characteristics" and "-sectorsize". Both require
       
   790 ** an argument. For -sectorsize, this is the simulated sector size in
       
   791 ** bytes. For -characteristics, the argument must be a list of io-capability
       
   792 ** flags to simulate. Valid flags are "atomic", "atomic512", "atomic1K",
       
   793 ** "atomic2K", "atomic4K", "atomic8K", "atomic16K", "atomic32K", 
       
   794 ** "atomic64K", "sequential" and "safe_append".
       
   795 **
       
   796 ** Example:
       
   797 **
       
   798 **   sqlite_crashparams -sect 1024 -char {atomic sequential} ./test.db 1
       
   799 **
       
   800 */
       
   801 static int crashParamsObjCmd(
       
   802   void * clientData,
       
   803   Tcl_Interp *interp,
       
   804   int objc,
       
   805   Tcl_Obj *CONST objv[]
       
   806 ){
       
   807   int iDelay;
       
   808   const char *zCrashFile;
       
   809   int nCrashFile, iDc, iSectorSize;
       
   810 
       
   811   iDc = -1;
       
   812   iSectorSize = -1;
       
   813 
       
   814   if( objc<3 ){
       
   815     Tcl_WrongNumArgs(interp, 1, objv, "?OPTIONS? DELAY CRASHFILE");
       
   816     goto error;
       
   817   }
       
   818 
       
   819   zCrashFile = Tcl_GetStringFromObj(objv[objc-1], &nCrashFile);
       
   820   if( nCrashFile>=sizeof(g.zCrashFile) ){
       
   821     Tcl_AppendResult(interp, "Filename is too long: \"", zCrashFile, "\"", 0);
       
   822     goto error;
       
   823   }
       
   824   if( Tcl_GetIntFromObj(interp, objv[objc-2], &iDelay) ){
       
   825     goto error;
       
   826   }
       
   827 
       
   828   if( processDevSymArgs(interp, objc-3, &objv[1], &iDc, &iSectorSize) ){
       
   829     return TCL_ERROR;
       
   830   }
       
   831 
       
   832   if( iDc>=0 ){
       
   833     g.iDeviceCharacteristics = iDc;
       
   834   }
       
   835   if( iSectorSize>=0 ){
       
   836     g.iSectorSize = iSectorSize;
       
   837   }
       
   838 
       
   839   g.iCrash = iDelay;
       
   840   memcpy(g.zCrashFile, zCrashFile, nCrashFile+1);
       
   841   sqlite3CrashTestEnable = 1;
       
   842   return TCL_OK;
       
   843 
       
   844 error:
       
   845   return TCL_ERROR;
       
   846 }
       
   847 
       
   848 static int devSymObjCmd(
       
   849   void * clientData,
       
   850   Tcl_Interp *interp,
       
   851   int objc,
       
   852   Tcl_Obj *CONST objv[]
       
   853 ){
       
   854   void devsym_register(int iDeviceChar, int iSectorSize);
       
   855 
       
   856   int iDc = -1;
       
   857   int iSectorSize = -1;
       
   858 
       
   859   if( processDevSymArgs(interp, objc-1, &objv[1], &iDc, &iSectorSize) ){
       
   860     return TCL_ERROR;
       
   861   }
       
   862   devsym_register(iDc, iSectorSize);
       
   863 
       
   864   return TCL_OK;
       
   865 }
       
   866 
       
   867 #endif /* SQLITE_OMIT_DISKIO */
       
   868 
       
   869 /*
       
   870 ** This procedure registers the TCL procedures defined in this file.
       
   871 */
       
   872 int Sqlitetest6_Init(Tcl_Interp *interp){
       
   873 #ifndef SQLITE_OMIT_DISKIO
       
   874   Tcl_CreateObjCommand(interp, "sqlite3_crash_enable", crashEnableCmd, 0, 0);
       
   875   Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0);
       
   876   Tcl_CreateObjCommand(interp, "sqlite3_simulate_device", devSymObjCmd, 0, 0);
       
   877 #endif
       
   878   return TCL_OK;
       
   879 }
       
   880 
       
   881 #endif /* SQLITE_TEST */