modernc.org/cc@v1.0.1/v2/testdata/_sqlite/src/test6.c (about)

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