| OLD | NEW | 
 | (Empty) | 
|    1 /* |  | 
|    2 ** 2008 Jan 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 for a VFS layer that acts as a wrapper around |  | 
|   14 ** an existing VFS. The code in this file attempts to verify that SQLite |  | 
|   15 ** correctly populates and syncs a journal file before writing to a |  | 
|   16 ** corresponding database file. |  | 
|   17 ** |  | 
|   18 ** $Id: test_journal.c,v 1.17 2009/06/26 10:39:36 danielk1977 Exp $ |  | 
|   19 */ |  | 
|   20 #if SQLITE_TEST          /* This file is used for testing only */ |  | 
|   21  |  | 
|   22 #include "sqlite3.h" |  | 
|   23 #include "sqliteInt.h" |  | 
|   24  |  | 
|   25 /* |  | 
|   26 ** INTERFACE |  | 
|   27 ** |  | 
|   28 **   The public interface to this wrapper VFS is two functions: |  | 
|   29 ** |  | 
|   30 **     jt_register() |  | 
|   31 **     jt_unregister() |  | 
|   32 ** |  | 
|   33 **   See header comments associated with those two functions below for  |  | 
|   34 **   details. |  | 
|   35 ** |  | 
|   36 ** LIMITATIONS |  | 
|   37 ** |  | 
|   38 **   This wrapper will not work if "PRAGMA synchronous = off" is used. |  | 
|   39 ** |  | 
|   40 ** OPERATION |  | 
|   41 ** |  | 
|   42 **  Starting a Transaction: |  | 
|   43 ** |  | 
|   44 **   When a write-transaction is started, the contents of the database is |  | 
|   45 **   inspected and the following data stored as part of the database file  |  | 
|   46 **   handle (type struct jt_file): |  | 
|   47 ** |  | 
|   48 **     a) The page-size of the database file. |  | 
|   49 **     b) The number of pages that are in the database file. |  | 
|   50 **     c) The set of page numbers corresponding to free-list leaf pages. |  | 
|   51 **     d) A check-sum for every page in the database file. |  | 
|   52 ** |  | 
|   53 **   The start of a write-transaction is deemed to have occurred when a  |  | 
|   54 **   28-byte journal header is written to byte offset 0 of the journal  |  | 
|   55 **   file. |  | 
|   56 ** |  | 
|   57 **  Syncing the Journal File: |  | 
|   58 ** |  | 
|   59 **   Whenever the xSync method is invoked to sync a journal-file, the |  | 
|   60 **   contents of the journal file are read. For each page written to |  | 
|   61 **   the journal file, a check-sum is calculated and compared to the   |  | 
|   62 **   check-sum calculated for the corresponding database page when the |  | 
|   63 **   write-transaction was initialized. The success of the comparison |  | 
|   64 **   is assert()ed. So if SQLite has written something other than the |  | 
|   65 **   original content to the database file, an assert() will fail. |  | 
|   66 ** |  | 
|   67 **   Additionally, the set of page numbers for which records exist in |  | 
|   68 **   the journal file is added to (unioned with) the set of page numbers |  | 
|   69 **   corresponding to free-list leaf pages collected when the  |  | 
|   70 **   write-transaction was initialized. This set comprises the page-numbers  |  | 
|   71 **   corresponding to those pages that SQLite may now safely modify. |  | 
|   72 ** |  | 
|   73 **  Writing to the Database File: |  | 
|   74 ** |  | 
|   75 **   When a block of data is written to a database file, the following |  | 
|   76 **   invariants are asserted: |  | 
|   77 ** |  | 
|   78 **     a) That the block of data is an aligned block of page-size bytes. |  | 
|   79 ** |  | 
|   80 **     b) That if the page being written did not exist when the  |  | 
|   81 **        transaction was started (i.e. the database file is growing), then |  | 
|   82 **        the journal-file must have been synced at least once since |  | 
|   83 **        the start of the transaction. |  | 
|   84 ** |  | 
|   85 **     c) That if the page being written did exist when the transaction  |  | 
|   86 **        was started, then the page must have either been a free-list |  | 
|   87 **        leaf page at the start of the transaction, or else must have |  | 
|   88 **        been stored in the journal file prior to the most recent sync. |  | 
|   89 ** |  | 
|   90 **  Closing a Transaction: |  | 
|   91 ** |  | 
|   92 **   When a transaction is closed, all data collected at the start of |  | 
|   93 **   the transaction, or following an xSync of a journal-file, is  |  | 
|   94 **   discarded. The end of a transaction is recognized when any one  |  | 
|   95 **   of the following occur: |  | 
|   96 ** |  | 
|   97 **     a) A block of zeroes (or anything else that is not a valid  |  | 
|   98 **        journal-header) is written to the start of the journal file. |  | 
|   99 ** |  | 
|  100 **     b) A journal file is truncated to zero bytes in size using xTruncate. |  | 
|  101 ** |  | 
|  102 **     c) The journal file is deleted using xDelete. |  | 
|  103 */ |  | 
|  104  |  | 
|  105 /* |  | 
|  106 ** Maximum pathname length supported by the jt backend. |  | 
|  107 */ |  | 
|  108 #define JT_MAX_PATHNAME 512 |  | 
|  109  |  | 
|  110 /* |  | 
|  111 ** Name used to identify this VFS. |  | 
|  112 */ |  | 
|  113 #define JT_VFS_NAME "jt" |  | 
|  114  |  | 
|  115 typedef struct jt_file jt_file; |  | 
|  116 struct jt_file { |  | 
|  117   sqlite3_file base; |  | 
|  118   const char *zName;       /* Name of open file */ |  | 
|  119   int flags;               /* Flags the file was opened with */ |  | 
|  120  |  | 
|  121   /* The following are only used by database file file handles */ |  | 
|  122   int eLock;               /* Current lock held on the file */ |  | 
|  123   u32 nPage;               /* Size of file in pages when transaction started */ |  | 
|  124   u32 nPagesize;           /* Page size when transaction started */ |  | 
|  125   Bitvec *pWritable;       /* Bitvec of pages that may be written to the file */ |  | 
|  126   u32 *aCksum;             /* Checksum for first nPage pages */ |  | 
|  127   int nSync;               /* Number of times journal file has been synced */ |  | 
|  128  |  | 
|  129   /* Only used by journal file-handles */ |  | 
|  130   sqlite3_int64 iMaxOff;   /* Maximum offset written to this transaction */ |  | 
|  131  |  | 
|  132   jt_file *pNext;          /* All files are stored in a linked list */ |  | 
|  133   sqlite3_file *pReal;     /* The file handle for the underlying vfs */ |  | 
|  134 }; |  | 
|  135  |  | 
|  136 /* |  | 
|  137 ** Method declarations for jt_file. |  | 
|  138 */ |  | 
|  139 static int jtClose(sqlite3_file*); |  | 
|  140 static int jtRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); |  | 
|  141 static int jtWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); |  | 
|  142 static int jtTruncate(sqlite3_file*, sqlite3_int64 size); |  | 
|  143 static int jtSync(sqlite3_file*, int flags); |  | 
|  144 static int jtFileSize(sqlite3_file*, sqlite3_int64 *pSize); |  | 
|  145 static int jtLock(sqlite3_file*, int); |  | 
|  146 static int jtUnlock(sqlite3_file*, int); |  | 
|  147 static int jtCheckReservedLock(sqlite3_file*, int *); |  | 
|  148 static int jtFileControl(sqlite3_file*, int op, void *pArg); |  | 
|  149 static int jtSectorSize(sqlite3_file*); |  | 
|  150 static int jtDeviceCharacteristics(sqlite3_file*); |  | 
|  151  |  | 
|  152 /* |  | 
|  153 ** Method declarations for jt_vfs. |  | 
|  154 */ |  | 
|  155 static int jtOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); |  | 
|  156 static int jtDelete(sqlite3_vfs*, const char *zName, int syncDir); |  | 
|  157 static int jtAccess(sqlite3_vfs*, const char *zName, int flags, int *); |  | 
|  158 static int jtFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); |  | 
|  159 static void *jtDlOpen(sqlite3_vfs*, const char *zFilename); |  | 
|  160 static void jtDlError(sqlite3_vfs*, int nByte, char *zErrMsg); |  | 
|  161 static void (*jtDlSym(sqlite3_vfs*,void*, const char *zSymbol))(void); |  | 
|  162 static void jtDlClose(sqlite3_vfs*, void*); |  | 
|  163 static int jtRandomness(sqlite3_vfs*, int nByte, char *zOut); |  | 
|  164 static int jtSleep(sqlite3_vfs*, int microseconds); |  | 
|  165 static int jtCurrentTime(sqlite3_vfs*, double*); |  | 
|  166  |  | 
|  167 static sqlite3_vfs jt_vfs = { |  | 
|  168   1,                             /* iVersion */ |  | 
|  169   sizeof(jt_file),               /* szOsFile */ |  | 
|  170   JT_MAX_PATHNAME,               /* mxPathname */ |  | 
|  171   0,                             /* pNext */ |  | 
|  172   JT_VFS_NAME,                   /* zName */ |  | 
|  173   0,                             /* pAppData */ |  | 
|  174   jtOpen,                        /* xOpen */ |  | 
|  175   jtDelete,                      /* xDelete */ |  | 
|  176   jtAccess,                      /* xAccess */ |  | 
|  177   jtFullPathname,                /* xFullPathname */ |  | 
|  178   jtDlOpen,                      /* xDlOpen */ |  | 
|  179   jtDlError,                     /* xDlError */ |  | 
|  180   jtDlSym,                       /* xDlSym */ |  | 
|  181   jtDlClose,                     /* xDlClose */ |  | 
|  182   jtRandomness,                  /* xRandomness */ |  | 
|  183   jtSleep,                       /* xSleep */ |  | 
|  184   jtCurrentTime                  /* xCurrentTime */ |  | 
|  185 }; |  | 
|  186  |  | 
|  187 static sqlite3_io_methods jt_io_methods = { |  | 
|  188   1,                             /* iVersion */ |  | 
|  189   jtClose,                       /* xClose */ |  | 
|  190   jtRead,                        /* xRead */ |  | 
|  191   jtWrite,                       /* xWrite */ |  | 
|  192   jtTruncate,                    /* xTruncate */ |  | 
|  193   jtSync,                        /* xSync */ |  | 
|  194   jtFileSize,                    /* xFileSize */ |  | 
|  195   jtLock,                        /* xLock */ |  | 
|  196   jtUnlock,                      /* xUnlock */ |  | 
|  197   jtCheckReservedLock,           /* xCheckReservedLock */ |  | 
|  198   jtFileControl,                 /* xFileControl */ |  | 
|  199   jtSectorSize,                  /* xSectorSize */ |  | 
|  200   jtDeviceCharacteristics        /* xDeviceCharacteristics */ |  | 
|  201 }; |  | 
|  202  |  | 
|  203 struct JtGlobal { |  | 
|  204   sqlite3_vfs *pVfs;             /* Parent VFS */ |  | 
|  205   jt_file *pList;                /* List of all open files */ |  | 
|  206 }; |  | 
|  207 static struct JtGlobal g = {0, 0}; |  | 
|  208  |  | 
|  209 /* |  | 
|  210 ** Functions to obtain and relinquish a mutex to protect g.pList. The |  | 
|  211 ** STATIC_PRNG mutex is reused, purely for the sake of convenience. |  | 
|  212 */ |  | 
|  213 static void enterJtMutex(void){ |  | 
|  214   sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG)); |  | 
|  215 } |  | 
|  216 static void leaveJtMutex(void){ |  | 
|  217   sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG)); |  | 
|  218 } |  | 
|  219  |  | 
|  220 extern int sqlite3_io_error_pending; |  | 
|  221 extern int sqlite3_io_error_hit; |  | 
|  222 static void stop_ioerr_simulation(int *piSave, int *piSave2){ |  | 
|  223   *piSave = sqlite3_io_error_pending; |  | 
|  224   *piSave2 = sqlite3_io_error_hit; |  | 
|  225   sqlite3_io_error_pending = -1; |  | 
|  226   sqlite3_io_error_hit = 0; |  | 
|  227 } |  | 
|  228 static void start_ioerr_simulation(int iSave, int iSave2){ |  | 
|  229   sqlite3_io_error_pending = iSave; |  | 
|  230   sqlite3_io_error_hit = iSave2; |  | 
|  231 } |  | 
|  232  |  | 
|  233 /* |  | 
|  234 ** The jt_file pointed to by the argument may or may not be a file-handle |  | 
|  235 ** open on a main database file. If it is, and a transaction is currently |  | 
|  236 ** opened on the file, then discard all transaction related data. |  | 
|  237 */ |  | 
|  238 static void closeTransaction(jt_file *p){ |  | 
|  239   sqlite3BitvecDestroy(p->pWritable); |  | 
|  240   sqlite3_free(p->aCksum); |  | 
|  241   p->pWritable = 0; |  | 
|  242   p->aCksum = 0; |  | 
|  243   p->nSync = 0; |  | 
|  244 } |  | 
|  245  |  | 
|  246 /* |  | 
|  247 ** Close an jt-file. |  | 
|  248 */ |  | 
|  249 static int jtClose(sqlite3_file *pFile){ |  | 
|  250   jt_file **pp; |  | 
|  251   jt_file *p = (jt_file *)pFile; |  | 
|  252  |  | 
|  253   closeTransaction(p); |  | 
|  254   enterJtMutex(); |  | 
|  255   if( p->zName ){ |  | 
|  256     for(pp=&g.pList; *pp!=p; pp=&(*pp)->pNext); |  | 
|  257     *pp = p->pNext; |  | 
|  258   } |  | 
|  259   leaveJtMutex(); |  | 
|  260   return sqlite3OsClose(p->pReal); |  | 
|  261 } |  | 
|  262  |  | 
|  263 /* |  | 
|  264 ** Read data from an jt-file. |  | 
|  265 */ |  | 
|  266 static int jtRead( |  | 
|  267   sqlite3_file *pFile,  |  | 
|  268   void *zBuf,  |  | 
|  269   int iAmt,  |  | 
|  270   sqlite_int64 iOfst |  | 
|  271 ){ |  | 
|  272   jt_file *p = (jt_file *)pFile; |  | 
|  273   return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst); |  | 
|  274 } |  | 
|  275  |  | 
|  276 /* |  | 
|  277 ** Parameter zJournal is the name of a journal file that is currently  |  | 
|  278 ** open. This function locates and returns the handle opened on the |  | 
|  279 ** corresponding database file by the pager that currently has the |  | 
|  280 ** journal file opened. This file-handle is identified by the  |  | 
|  281 ** following properties: |  | 
|  282 ** |  | 
|  283 **   a) SQLITE_OPEN_MAIN_DB was specified when the file was opened. |  | 
|  284 ** |  | 
|  285 **   b) The file-name specified when the file was opened matches |  | 
|  286 **      all but the final 8 characters of the journal file name. |  | 
|  287 ** |  | 
|  288 **   c) There is currently a reserved lock on the file. |  | 
|  289 **/ |  | 
|  290 static jt_file *locateDatabaseHandle(const char *zJournal){ |  | 
|  291   jt_file *pMain = 0; |  | 
|  292   enterJtMutex(); |  | 
|  293   for(pMain=g.pList; pMain; pMain=pMain->pNext){ |  | 
|  294     int nName = strlen(zJournal) - strlen("-journal"); |  | 
|  295     if( (pMain->flags&SQLITE_OPEN_MAIN_DB) |  | 
|  296      && (strlen(pMain->zName)==nName) |  | 
|  297      && 0==memcmp(pMain->zName, zJournal, nName) |  | 
|  298      && (pMain->eLock>=SQLITE_LOCK_RESERVED) |  | 
|  299     ){ |  | 
|  300       break; |  | 
|  301     } |  | 
|  302   } |  | 
|  303   leaveJtMutex(); |  | 
|  304   return pMain; |  | 
|  305 } |  | 
|  306  |  | 
|  307 /* |  | 
|  308 ** Parameter z points to a buffer of 4 bytes in size containing a  |  | 
|  309 ** unsigned 32-bit integer stored in big-endian format. Decode the  |  | 
|  310 ** integer and return its value. |  | 
|  311 */ |  | 
|  312 static u32 decodeUint32(const unsigned char *z){ |  | 
|  313   return (z[0]<<24) + (z[1]<<16) + (z[2]<<8) + z[3]; |  | 
|  314 } |  | 
|  315  |  | 
|  316 /* |  | 
|  317 ** Calculate a checksum from the buffer of length n bytes pointed to |  | 
|  318 ** by parameter z. |  | 
|  319 */ |  | 
|  320 static u32 genCksum(const unsigned char *z, int n){ |  | 
|  321   int i; |  | 
|  322   u32 cksum = 0; |  | 
|  323   for(i=0; i<n; i++){ |  | 
|  324     cksum = cksum + z[i] + (cksum<<3); |  | 
|  325   } |  | 
|  326   return cksum; |  | 
|  327 } |  | 
|  328  |  | 
|  329 /* |  | 
|  330 ** The first argument, zBuf, points to a buffer containing a 28 byte |  | 
|  331 ** serialized journal header. This function deserializes four of the |  | 
|  332 ** integer fields contained in the journal header and writes their |  | 
|  333 ** values to the output variables. |  | 
|  334 ** |  | 
|  335 ** SQLITE_OK is returned if the journal-header is successfully  |  | 
|  336 ** decoded. Otherwise, SQLITE_ERROR. |  | 
|  337 */ |  | 
|  338 static int decodeJournalHdr( |  | 
|  339   const unsigned char *zBuf,         /* Input: 28 byte journal header */ |  | 
|  340   u32 *pnRec,                        /* Out: Number of journalled records */ |  | 
|  341   u32 *pnPage,                       /* Out: Original database page count */ |  | 
|  342   u32 *pnSector,                     /* Out: Sector size in bytes */ |  | 
|  343   u32 *pnPagesize                    /* Out: Page size in bytes */ |  | 
|  344 ){ |  | 
|  345   unsigned char aMagic[] = { 0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd7 }; |  | 
|  346   if( memcmp(aMagic, zBuf, 8) ) return SQLITE_ERROR; |  | 
|  347   if( pnRec ) *pnRec = decodeUint32(&zBuf[8]); |  | 
|  348   if( pnPage ) *pnPage = decodeUint32(&zBuf[16]); |  | 
|  349   if( pnSector ) *pnSector = decodeUint32(&zBuf[20]); |  | 
|  350   if( pnPagesize ) *pnPagesize = decodeUint32(&zBuf[24]); |  | 
|  351   return SQLITE_OK; |  | 
|  352 } |  | 
|  353  |  | 
|  354 /* |  | 
|  355 ** This function is called when a new transaction is opened, just after |  | 
|  356 ** the first journal-header is written to the journal file. |  | 
|  357 */ |  | 
|  358 static int openTransaction(jt_file *pMain, jt_file *pJournal){ |  | 
|  359   unsigned char *aData; |  | 
|  360   sqlite3_file *p = pMain->pReal; |  | 
|  361   int rc = SQLITE_OK; |  | 
|  362  |  | 
|  363   aData = sqlite3_malloc(pMain->nPagesize); |  | 
|  364   pMain->pWritable = sqlite3BitvecCreate(pMain->nPage); |  | 
|  365   pMain->aCksum = sqlite3_malloc(sizeof(u32) * (pMain->nPage + 1)); |  | 
|  366   pJournal->iMaxOff = 0; |  | 
|  367  |  | 
|  368   if( !pMain->pWritable || !pMain->aCksum || !aData ){ |  | 
|  369     rc = SQLITE_IOERR_NOMEM; |  | 
|  370   }else if( pMain->nPage>0 ){ |  | 
|  371     u32 iTrunk; |  | 
|  372     int iSave; |  | 
|  373     int iSave2; |  | 
|  374  |  | 
|  375     stop_ioerr_simulation(&iSave, &iSave2); |  | 
|  376  |  | 
|  377     /* Read the database free-list. Add the page-number for each free-list |  | 
|  378     ** leaf to the jt_file.pWritable bitvec. |  | 
|  379     */ |  | 
|  380     rc = sqlite3OsRead(p, aData, pMain->nPagesize, 0); |  | 
|  381     iTrunk = decodeUint32(&aData[32]); |  | 
|  382     while( rc==SQLITE_OK && iTrunk>0 ){ |  | 
|  383       u32 nLeaf; |  | 
|  384       u32 iLeaf; |  | 
|  385       sqlite3_int64 iOff = (iTrunk-1)*pMain->nPagesize; |  | 
|  386       rc = sqlite3OsRead(p, aData, pMain->nPagesize, iOff); |  | 
|  387       nLeaf = decodeUint32(&aData[4]); |  | 
|  388       for(iLeaf=0; rc==SQLITE_OK && iLeaf<nLeaf; iLeaf++){ |  | 
|  389         u32 pgno = decodeUint32(&aData[8+4*iLeaf]); |  | 
|  390         sqlite3BitvecSet(pMain->pWritable, pgno); |  | 
|  391       } |  | 
|  392       iTrunk = decodeUint32(aData); |  | 
|  393     } |  | 
|  394  |  | 
|  395     /* Calculate and store a checksum for each page in the database file. */ |  | 
|  396     if( rc==SQLITE_OK ){ |  | 
|  397       int ii; |  | 
|  398       for(ii=0; rc==SQLITE_OK && ii<pMain->nPage; ii++){ |  | 
|  399         i64 iOff = (i64)(pMain->nPagesize) * (i64)ii; |  | 
|  400         if( iOff==PENDING_BYTE ) continue; |  | 
|  401         rc = sqlite3OsRead(pMain->pReal, aData, pMain->nPagesize, iOff); |  | 
|  402         pMain->aCksum[ii] = genCksum(aData, pMain->nPagesize); |  | 
|  403       } |  | 
|  404     } |  | 
|  405  |  | 
|  406     start_ioerr_simulation(iSave, iSave2); |  | 
|  407   } |  | 
|  408  |  | 
|  409   sqlite3_free(aData); |  | 
|  410   return rc; |  | 
|  411 } |  | 
|  412  |  | 
|  413 /* |  | 
|  414 ** The first argument to this function is a handle open on a journal file. |  | 
|  415 ** This function reads the journal file and adds the page number for each |  | 
|  416 ** page in the journal to the Bitvec object passed as the second argument. |  | 
|  417 */ |  | 
|  418 static int readJournalFile(jt_file *p, jt_file *pMain){ |  | 
|  419   int rc = SQLITE_OK; |  | 
|  420   unsigned char zBuf[28]; |  | 
|  421   sqlite3_file *pReal = p->pReal; |  | 
|  422   sqlite3_int64 iOff = 0; |  | 
|  423   sqlite3_int64 iSize = p->iMaxOff; |  | 
|  424   unsigned char *aPage; |  | 
|  425   int iSave; |  | 
|  426   int iSave2; |  | 
|  427  |  | 
|  428   aPage = sqlite3_malloc(pMain->nPagesize); |  | 
|  429   if( !aPage ){ |  | 
|  430     return SQLITE_IOERR_NOMEM; |  | 
|  431   } |  | 
|  432  |  | 
|  433   stop_ioerr_simulation(&iSave, &iSave2); |  | 
|  434  |  | 
|  435   while( rc==SQLITE_OK && iOff<iSize ){ |  | 
|  436     u32 nRec, nPage, nSector, nPagesize; |  | 
|  437     u32 ii; |  | 
|  438  |  | 
|  439     /* Read and decode the next journal-header from the journal file. */ |  | 
|  440     rc = sqlite3OsRead(pReal, zBuf, 28, iOff); |  | 
|  441     if( rc!=SQLITE_OK  |  | 
|  442      || decodeJournalHdr(zBuf, &nRec, &nPage, &nSector, &nPagesize)  |  | 
|  443     ){ |  | 
|  444       goto finish_rjf; |  | 
|  445     } |  | 
|  446     iOff += nSector; |  | 
|  447  |  | 
|  448     if( nRec==0 ){ |  | 
|  449       /* A trick. There might be another journal-header immediately  |  | 
|  450       ** following this one. In this case, 0 records means 0 records,  |  | 
|  451       ** not "read until the end of the file". See also ticket #2565. |  | 
|  452       */ |  | 
|  453       if( iSize>=(iOff+nSector) ){ |  | 
|  454         rc = sqlite3OsRead(pReal, zBuf, 28, iOff); |  | 
|  455         if( rc!=SQLITE_OK || 0==decodeJournalHdr(zBuf, 0, 0, 0, 0) ){ |  | 
|  456           continue; |  | 
|  457         } |  | 
|  458       } |  | 
|  459       nRec = (iSize-iOff) / (pMain->nPagesize+8); |  | 
|  460     } |  | 
|  461  |  | 
|  462     /* Read all the records that follow the journal-header just read. */ |  | 
|  463     for(ii=0; rc==SQLITE_OK && ii<nRec && iOff<iSize; ii++){ |  | 
|  464       u32 pgno; |  | 
|  465       rc = sqlite3OsRead(pReal, zBuf, 4, iOff); |  | 
|  466       if( rc==SQLITE_OK ){ |  | 
|  467         pgno = decodeUint32(zBuf); |  | 
|  468         if( pgno>0 && pgno<=pMain->nPage ){ |  | 
|  469           if( 0==sqlite3BitvecTest(pMain->pWritable, pgno) ){ |  | 
|  470             rc = sqlite3OsRead(pReal, aPage, pMain->nPagesize, iOff+4); |  | 
|  471             if( rc==SQLITE_OK ){ |  | 
|  472               u32 cksum = genCksum(aPage, pMain->nPagesize); |  | 
|  473               assert( cksum==pMain->aCksum[pgno-1] ); |  | 
|  474             } |  | 
|  475           } |  | 
|  476           sqlite3BitvecSet(pMain->pWritable, pgno); |  | 
|  477         } |  | 
|  478         iOff += (8 + pMain->nPagesize); |  | 
|  479       } |  | 
|  480     } |  | 
|  481  |  | 
|  482     iOff = ((iOff + (nSector-1)) / nSector) * nSector; |  | 
|  483   } |  | 
|  484  |  | 
|  485 finish_rjf: |  | 
|  486   start_ioerr_simulation(iSave, iSave2); |  | 
|  487   sqlite3_free(aPage); |  | 
|  488   if( rc==SQLITE_IOERR_SHORT_READ ){ |  | 
|  489     rc = SQLITE_OK; |  | 
|  490   } |  | 
|  491   return rc; |  | 
|  492 } |  | 
|  493  |  | 
|  494  |  | 
|  495 /* |  | 
|  496 ** Write data to an jt-file. |  | 
|  497 */ |  | 
|  498 static int jtWrite( |  | 
|  499   sqlite3_file *pFile,  |  | 
|  500   const void *zBuf,  |  | 
|  501   int iAmt,  |  | 
|  502   sqlite_int64 iOfst |  | 
|  503 ){ |  | 
|  504   int rc; |  | 
|  505   jt_file *p = (jt_file *)pFile; |  | 
|  506   if( p->flags&SQLITE_OPEN_MAIN_JOURNAL ){ |  | 
|  507     if( iOfst==0 ){ |  | 
|  508       jt_file *pMain = locateDatabaseHandle(p->zName); |  | 
|  509       assert( pMain ); |  | 
|  510    |  | 
|  511       if( iAmt==28 ){ |  | 
|  512         /* Zeroing the first journal-file header. This is the end of a |  | 
|  513         ** transaction. */ |  | 
|  514         closeTransaction(pMain); |  | 
|  515       }else if( iAmt!=12 ){ |  | 
|  516         /* Writing the first journal header to a journal file. This happens |  | 
|  517         ** when a transaction is first started.  */ |  | 
|  518         u8 *z = (u8 *)zBuf; |  | 
|  519         pMain->nPage = decodeUint32(&z[16]); |  | 
|  520         pMain->nPagesize = decodeUint32(&z[24]); |  | 
|  521         if( SQLITE_OK!=(rc=openTransaction(pMain, p)) ){ |  | 
|  522           return rc; |  | 
|  523         } |  | 
|  524       } |  | 
|  525     } |  | 
|  526     if( p->iMaxOff<(iOfst + iAmt) ){ |  | 
|  527       p->iMaxOff = iOfst + iAmt; |  | 
|  528     } |  | 
|  529   } |  | 
|  530  |  | 
|  531   if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){ |  | 
|  532     if( iAmt<p->nPagesize  |  | 
|  533      && p->nPagesize%iAmt==0  |  | 
|  534      && iOfst>=(PENDING_BYTE+512)  |  | 
|  535      && iOfst+iAmt<=PENDING_BYTE+p->nPagesize |  | 
|  536     ){ |  | 
|  537       /* No-op. This special case is hit when the backup code is copying a |  | 
|  538       ** to a database with a larger page-size than the source database and |  | 
|  539       ** it needs to fill in the non-locking-region part of the original |  | 
|  540       ** pending-byte page. |  | 
|  541       */ |  | 
|  542     }else{ |  | 
|  543       u32 pgno = iOfst/p->nPagesize + 1; |  | 
|  544       assert( (iAmt==1||iAmt==p->nPagesize) && ((iOfst+iAmt)%p->nPagesize)==0 ); |  | 
|  545       assert( pgno<=p->nPage || p->nSync>0 ); |  | 
|  546       assert( pgno>p->nPage || sqlite3BitvecTest(p->pWritable, pgno) ); |  | 
|  547     } |  | 
|  548   } |  | 
|  549  |  | 
|  550   rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst); |  | 
|  551   if( (p->flags&SQLITE_OPEN_MAIN_JOURNAL) && iAmt==12 ){ |  | 
|  552     jt_file *pMain = locateDatabaseHandle(p->zName); |  | 
|  553     int rc2 = readJournalFile(p, pMain); |  | 
|  554     if( rc==SQLITE_OK ) rc = rc2; |  | 
|  555   } |  | 
|  556   return rc; |  | 
|  557 } |  | 
|  558  |  | 
|  559 /* |  | 
|  560 ** Truncate an jt-file. |  | 
|  561 */ |  | 
|  562 static int jtTruncate(sqlite3_file *pFile, sqlite_int64 size){ |  | 
|  563   jt_file *p = (jt_file *)pFile; |  | 
|  564   if( p->flags&SQLITE_OPEN_MAIN_JOURNAL && size==0 ){ |  | 
|  565     /* Truncating a journal file. This is the end of a transaction. */ |  | 
|  566     jt_file *pMain = locateDatabaseHandle(p->zName); |  | 
|  567     closeTransaction(pMain); |  | 
|  568   } |  | 
|  569   if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){ |  | 
|  570     u32 pgno; |  | 
|  571     u32 locking_page = (u32)(PENDING_BYTE/p->nPagesize+1); |  | 
|  572     for(pgno=size/p->nPagesize+1; pgno<=p->nPage; pgno++){ |  | 
|  573       assert( pgno==locking_page || sqlite3BitvecTest(p->pWritable, pgno) ); |  | 
|  574     } |  | 
|  575   } |  | 
|  576   return sqlite3OsTruncate(p->pReal, size); |  | 
|  577 } |  | 
|  578  |  | 
|  579 /* |  | 
|  580 ** Sync an jt-file. |  | 
|  581 */ |  | 
|  582 static int jtSync(sqlite3_file *pFile, int flags){ |  | 
|  583   jt_file *p = (jt_file *)pFile; |  | 
|  584  |  | 
|  585   if( p->flags&SQLITE_OPEN_MAIN_JOURNAL ){ |  | 
|  586     int rc; |  | 
|  587     jt_file *pMain;                   /* The associated database file */ |  | 
|  588  |  | 
|  589     /* The journal file is being synced. At this point, we inspect the  |  | 
|  590     ** contents of the file up to this point and set each bit in the  |  | 
|  591     ** jt_file.pWritable bitvec of the main database file associated with |  | 
|  592     ** this journal file. |  | 
|  593     */ |  | 
|  594     pMain = locateDatabaseHandle(p->zName); |  | 
|  595     assert(pMain); |  | 
|  596  |  | 
|  597     /* Set the bitvec values */ |  | 
|  598     if( pMain->pWritable ){ |  | 
|  599       pMain->nSync++; |  | 
|  600       rc = readJournalFile(p, pMain); |  | 
|  601       if( rc!=SQLITE_OK ){ |  | 
|  602         return rc; |  | 
|  603       } |  | 
|  604     } |  | 
|  605   } |  | 
|  606  |  | 
|  607   return sqlite3OsSync(p->pReal, flags); |  | 
|  608 } |  | 
|  609  |  | 
|  610 /* |  | 
|  611 ** Return the current file-size of an jt-file. |  | 
|  612 */ |  | 
|  613 static int jtFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ |  | 
|  614   jt_file *p = (jt_file *)pFile; |  | 
|  615   return sqlite3OsFileSize(p->pReal, pSize); |  | 
|  616 } |  | 
|  617  |  | 
|  618 /* |  | 
|  619 ** Lock an jt-file. |  | 
|  620 */ |  | 
|  621 static int jtLock(sqlite3_file *pFile, int eLock){ |  | 
|  622   int rc; |  | 
|  623   jt_file *p = (jt_file *)pFile; |  | 
|  624   rc = sqlite3OsLock(p->pReal, eLock); |  | 
|  625   if( rc==SQLITE_OK && eLock>p->eLock ){ |  | 
|  626     p->eLock = eLock; |  | 
|  627   } |  | 
|  628   return rc; |  | 
|  629 } |  | 
|  630  |  | 
|  631 /* |  | 
|  632 ** Unlock an jt-file. |  | 
|  633 */ |  | 
|  634 static int jtUnlock(sqlite3_file *pFile, int eLock){ |  | 
|  635   int rc; |  | 
|  636   jt_file *p = (jt_file *)pFile; |  | 
|  637   rc = sqlite3OsUnlock(p->pReal, eLock); |  | 
|  638   if( rc==SQLITE_OK && eLock<p->eLock ){ |  | 
|  639     p->eLock = eLock; |  | 
|  640   } |  | 
|  641   return rc; |  | 
|  642 } |  | 
|  643  |  | 
|  644 /* |  | 
|  645 ** Check if another file-handle holds a RESERVED lock on an jt-file. |  | 
|  646 */ |  | 
|  647 static int jtCheckReservedLock(sqlite3_file *pFile, int *pResOut){ |  | 
|  648   jt_file *p = (jt_file *)pFile; |  | 
|  649   return sqlite3OsCheckReservedLock(p->pReal, pResOut); |  | 
|  650 } |  | 
|  651  |  | 
|  652 /* |  | 
|  653 ** File control method. For custom operations on an jt-file. |  | 
|  654 */ |  | 
|  655 static int jtFileControl(sqlite3_file *pFile, int op, void *pArg){ |  | 
|  656   jt_file *p = (jt_file *)pFile; |  | 
|  657   return sqlite3OsFileControl(p->pReal, op, pArg); |  | 
|  658 } |  | 
|  659  |  | 
|  660 /* |  | 
|  661 ** Return the sector-size in bytes for an jt-file. |  | 
|  662 */ |  | 
|  663 static int jtSectorSize(sqlite3_file *pFile){ |  | 
|  664   jt_file *p = (jt_file *)pFile; |  | 
|  665   return sqlite3OsSectorSize(p->pReal); |  | 
|  666 } |  | 
|  667  |  | 
|  668 /* |  | 
|  669 ** Return the device characteristic flags supported by an jt-file. |  | 
|  670 */ |  | 
|  671 static int jtDeviceCharacteristics(sqlite3_file *pFile){ |  | 
|  672   jt_file *p = (jt_file *)pFile; |  | 
|  673   return sqlite3OsDeviceCharacteristics(p->pReal); |  | 
|  674 } |  | 
|  675  |  | 
|  676 /* |  | 
|  677 ** Open an jt file handle. |  | 
|  678 */ |  | 
|  679 static int jtOpen( |  | 
|  680   sqlite3_vfs *pVfs, |  | 
|  681   const char *zName, |  | 
|  682   sqlite3_file *pFile, |  | 
|  683   int flags, |  | 
|  684   int *pOutFlags |  | 
|  685 ){ |  | 
|  686   int rc; |  | 
|  687   jt_file *p = (jt_file *)pFile; |  | 
|  688   pFile->pMethods = 0; |  | 
|  689   p->pReal = (sqlite3_file *)&p[1]; |  | 
|  690   p->pReal->pMethods = 0; |  | 
|  691   rc = sqlite3OsOpen(g.pVfs, zName, p->pReal, flags, pOutFlags); |  | 
|  692   assert( rc==SQLITE_OK || p->pReal->pMethods==0 ); |  | 
|  693   if( rc==SQLITE_OK ){ |  | 
|  694     pFile->pMethods = &jt_io_methods; |  | 
|  695     p->eLock = 0; |  | 
|  696     p->zName = zName; |  | 
|  697     p->flags = flags; |  | 
|  698     p->pNext = 0; |  | 
|  699     p->pWritable = 0; |  | 
|  700     p->aCksum = 0; |  | 
|  701     enterJtMutex(); |  | 
|  702     if( zName ){ |  | 
|  703       p->pNext = g.pList; |  | 
|  704       g.pList = p; |  | 
|  705     } |  | 
|  706     leaveJtMutex(); |  | 
|  707   } |  | 
|  708   return rc; |  | 
|  709 } |  | 
|  710  |  | 
|  711 /* |  | 
|  712 ** Delete the file located at zPath. If the dirSync argument is true, |  | 
|  713 ** ensure the file-system modifications are synced to disk before |  | 
|  714 ** returning. |  | 
|  715 */ |  | 
|  716 static int jtDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ |  | 
|  717   int nPath = strlen(zPath); |  | 
|  718   if( nPath>8 && 0==strcmp("-journal", &zPath[nPath-8]) ){ |  | 
|  719     /* Deleting a journal file. The end of a transaction. */ |  | 
|  720     jt_file *pMain = locateDatabaseHandle(zPath); |  | 
|  721     if( pMain ){ |  | 
|  722       closeTransaction(pMain); |  | 
|  723     } |  | 
|  724   } |  | 
|  725  |  | 
|  726   return sqlite3OsDelete(g.pVfs, zPath, dirSync); |  | 
|  727 } |  | 
|  728  |  | 
|  729 /* |  | 
|  730 ** Test for access permissions. Return true if the requested permission |  | 
|  731 ** is available, or false otherwise. |  | 
|  732 */ |  | 
|  733 static int jtAccess( |  | 
|  734   sqlite3_vfs *pVfs,  |  | 
|  735   const char *zPath,  |  | 
|  736   int flags,  |  | 
|  737   int *pResOut |  | 
|  738 ){ |  | 
|  739   return sqlite3OsAccess(g.pVfs, zPath, flags, pResOut); |  | 
|  740 } |  | 
|  741  |  | 
|  742 /* |  | 
|  743 ** Populate buffer zOut with the full canonical pathname corresponding |  | 
|  744 ** to the pathname in zPath. zOut is guaranteed to point to a buffer |  | 
|  745 ** of at least (JT_MAX_PATHNAME+1) bytes. |  | 
|  746 */ |  | 
|  747 static int jtFullPathname( |  | 
|  748   sqlite3_vfs *pVfs,  |  | 
|  749   const char *zPath,  |  | 
|  750   int nOut,  |  | 
|  751   char *zOut |  | 
|  752 ){ |  | 
|  753   return sqlite3OsFullPathname(g.pVfs, zPath, nOut, zOut); |  | 
|  754 } |  | 
|  755  |  | 
|  756 /* |  | 
|  757 ** Open the dynamic library located at zPath and return a handle. |  | 
|  758 */ |  | 
|  759 static void *jtDlOpen(sqlite3_vfs *pVfs, const char *zPath){ |  | 
|  760   return g.pVfs->xDlOpen(g.pVfs, zPath); |  | 
|  761 } |  | 
|  762  |  | 
|  763 /* |  | 
|  764 ** Populate the buffer zErrMsg (size nByte bytes) with a human readable |  | 
|  765 ** utf-8 string describing the most recent error encountered associated  |  | 
|  766 ** with dynamic libraries. |  | 
|  767 */ |  | 
|  768 static void jtDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ |  | 
|  769   g.pVfs->xDlError(g.pVfs, nByte, zErrMsg); |  | 
|  770 } |  | 
|  771  |  | 
|  772 /* |  | 
|  773 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle. |  | 
|  774 */ |  | 
|  775 static void (*jtDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ |  | 
|  776   return g.pVfs->xDlSym(g.pVfs, p, zSym); |  | 
|  777 } |  | 
|  778  |  | 
|  779 /* |  | 
|  780 ** Close the dynamic library handle pHandle. |  | 
|  781 */ |  | 
|  782 static void jtDlClose(sqlite3_vfs *pVfs, void *pHandle){ |  | 
|  783   g.pVfs->xDlClose(g.pVfs, pHandle); |  | 
|  784 } |  | 
|  785  |  | 
|  786 /* |  | 
|  787 ** Populate the buffer pointed to by zBufOut with nByte bytes of  |  | 
|  788 ** random data. |  | 
|  789 */ |  | 
|  790 static int jtRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ |  | 
|  791   return sqlite3OsRandomness(g.pVfs, nByte, zBufOut); |  | 
|  792 } |  | 
|  793  |  | 
|  794 /* |  | 
|  795 ** Sleep for nMicro microseconds. Return the number of microseconds  |  | 
|  796 ** actually slept. |  | 
|  797 */ |  | 
|  798 static int jtSleep(sqlite3_vfs *pVfs, int nMicro){ |  | 
|  799   return sqlite3OsSleep(g.pVfs, nMicro); |  | 
|  800 } |  | 
|  801  |  | 
|  802 /* |  | 
|  803 ** Return the current time as a Julian Day number in *pTimeOut. |  | 
|  804 */ |  | 
|  805 static int jtCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ |  | 
|  806   return sqlite3OsCurrentTime(g.pVfs, pTimeOut); |  | 
|  807 } |  | 
|  808  |  | 
|  809 /************************************************************************** |  | 
|  810 ** Start of public API. |  | 
|  811 */ |  | 
|  812  |  | 
|  813 /* |  | 
|  814 ** Configure the jt VFS as a wrapper around the VFS named by parameter  |  | 
|  815 ** zWrap. If the isDefault parameter is true, then the jt VFS is installed |  | 
|  816 ** as the new default VFS for SQLite connections. If isDefault is not |  | 
|  817 ** true, then the jt VFS is installed as non-default. In this case it |  | 
|  818 ** is available via its name, "jt". |  | 
|  819 */ |  | 
|  820 int jt_register(char *zWrap, int isDefault){ |  | 
|  821   g.pVfs = sqlite3_vfs_find(zWrap); |  | 
|  822   if( g.pVfs==0 ){ |  | 
|  823     return SQLITE_ERROR; |  | 
|  824   } |  | 
|  825   jt_vfs.szOsFile = sizeof(jt_file) + g.pVfs->szOsFile; |  | 
|  826   sqlite3_vfs_register(&jt_vfs, isDefault); |  | 
|  827   return SQLITE_OK; |  | 
|  828 } |  | 
|  829  |  | 
|  830 /* |  | 
|  831 ** Uninstall the jt VFS, if it is installed. |  | 
|  832 */ |  | 
|  833 void jt_unregister(void){ |  | 
|  834   sqlite3_vfs_unregister(&jt_vfs); |  | 
|  835 } |  | 
|  836  |  | 
|  837 #endif |  | 
| OLD | NEW |