/* ** Write data to an jt-file. */ static int jtWrite( sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite_int64 iOfst ){ int rc; jt_file *p = (jt_file *)pFile; if( p->flags&SQLITE_OPEN_MAIN_JOURNAL ){ if( iOfst==0 ){ jt_file *pMain = locateDatabaseHandle(p->zName); assert( pMain ); if( iAmt==28 ){ /* Zeroing the first journal-file header. This is the end of a ** transaction. */ closeTransaction(pMain); }else if( iAmt!=12 ){ /* Writing the first journal header to a journal file. This happens ** when a transaction is first started. */ u8 *z = (u8 *)zBuf; pMain->nPage = decodeUint32(&z[16]); pMain->nPagesize = decodeUint32(&z[24]); if( SQLITE_OK!=(rc=openTransaction(pMain, p)) ){ return rc; } } } if( p->iMaxOff<(iOfst + iAmt) ){ p->iMaxOff = iOfst + iAmt; } } if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){ if( iAmt<p->nPagesize && p->nPagesize%iAmt==0 && iOfst>=(PENDING_BYTE+512) && iOfst+iAmt<=PENDING_BYTE+p->nPagesize ){ /* No-op. This special case is hit when the backup code is copying a ** to a database with a larger page-size than the source database and ** it needs to fill in the non-locking-region part of the original ** pending-byte page. */ }else{ u32 pgno = iOfst/p->nPagesize + 1; assert( (iAmt==1||iAmt==p->nPagesize) && ((iOfst+iAmt)%p->nPagesize)==0 ); assert( pgno<=p->nPage || p->nSync>0 ); assert( pgno>p->nPage || sqlite3BitvecTest(p->pWritable, pgno) ); } } rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst); if( (p->flags&SQLITE_OPEN_MAIN_JOURNAL) && iAmt==12 ){ jt_file *pMain = locateDatabaseHandle(p->zName); int rc2 = readJournalFile(p, pMain); if( rc==SQLITE_OK ) rc = rc2; } return rc; }
static SQRESULT sq_BitVector_test(HSQUIRRELVM v){ SQ_FUNC_VARS_NO_TOP(v); GET_BitVector_INSTANCE(); SQ_GET_INTEGER(v, 2, int_pos); BV_CHECK_RANGE(); // int sqlite3BitvecTest(Bitvec*, u32) sq_pushinteger(v, sqlite3BitvecTest(self, (u32)int_pos)); return 1; }
static int jtWrite( sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite_int64 iOfst ){ int rc; jt_file *p = (jt_file *)pFile; if( p->flags&SQLITE_OPEN_MAIN_JOURNAL ){ if( iOfst==0 ){ jt_file *pMain = locateDatabaseHandle(p->zName); assert( pMain ); if( iAmt==28 ){ closeTransaction(pMain); }else if( iAmt!=12 ){ u8 *z = (u8 *)zBuf; pMain->nPage = decodeUint32(&z[16]); pMain->nPagesize = decodeUint32(&z[24]); if( SQLITE_OK!=(rc=openTransaction(pMain, p)) ){ return rc; } } } if( p->iMaxOff<(iOfst + iAmt) ){ p->iMaxOff = iOfst + iAmt; } } if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){ if( iAmt<p->nPagesize && p->nPagesize%iAmt==0 && iOfst>=(PENDING_BYTE+512) && iOfst+iAmt<=PENDING_BYTE+p->nPagesize ){ }else{ u32 pgno = iOfst/p->nPagesize + 1; assert( (iAmt==1||iAmt==p->nPagesize) && ((iOfst+iAmt)%p->nPagesize)==0 ); assert( pgno<=p->nPage || p->nSync>0 ); assert( pgno>p->nPage || sqlite3BitvecTest(p->pWritable, pgno) ); } } rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst); if( (p->flags&SQLITE_OPEN_MAIN_JOURNAL) && iAmt==12 ){ jt_file *pMain = locateDatabaseHandle(p->zName); int rc2 = readJournalFile(p, pMain); if( rc==SQLITE_OK ) rc = rc2; } return rc; }
/* ** Truncate an jt-file. */ static int jtTruncate(sqlite3_file *pFile, sqlite_int64 size){ jt_file *p = (jt_file *)pFile; if( p->flags&SQLITE_OPEN_MAIN_JOURNAL && size==0 ){ /* Truncating a journal file. This is the end of a transaction. */ jt_file *pMain = locateDatabaseHandle(p->zName); closeTransaction(pMain); } if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){ u32 pgno; u32 locking_page = (u32)(PENDING_BYTE/p->nPagesize+1); for(pgno=size/p->nPagesize+1; pgno<=p->nPage; pgno++){ assert( pgno==locking_page || sqlite3BitvecTest(p->pWritable, pgno) ); } } return sqlite3OsTruncate(p->pReal, size); }
/* ** Check to see if the i-th bit is set. Return true or false. ** If p is NULL (if the bitmap has not been created) or if ** i is out of range, then return false. */ int sqlite3BitvecTest(Bitvec *p, u32 i){ if( p==0 ) return 0; if( i>p->iSize || i==0 ) return 0; if( p->iSize<=BITVEC_NBIT ){ i--; return (p->u.aBitmap[i/8] & (1<<(i&7)))!=0; } if( p->iDivisor>0 ){ u32 bin = (i-1)/p->iDivisor; i = (i-1)%p->iDivisor + 1; return sqlite3BitvecTest(p->u.apSub[bin], i); }else{ u32 h = BITVEC_HASH(i); while( p->u.aHash[h] ){ if( p->u.aHash[h]==i ) return 1; h++; if( h>=BITVEC_NINT ) h = 0; } return 0; } }
/* ** The first argument to this function is a handle open on a journal file. ** This function reads the journal file and adds the page number for each ** page in the journal to the Bitvec object passed as the second argument. */ static int readJournalFile(jt_file *p, jt_file *pMain){ int rc = SQLITE_OK; unsigned char zBuf[28]; sqlite3_file *pReal = p->pReal; sqlite3_int64 iOff = 0; sqlite3_int64 iSize = p->iMaxOff; unsigned char *aPage; int iSave; int iSave2; aPage = sqlite3_malloc(pMain->nPagesize); if( !aPage ){ return SQLITE_IOERR_NOMEM; } stop_ioerr_simulation(&iSave, &iSave2); while( rc==SQLITE_OK && iOff<iSize ){ u32 nRec, nPage, nSector, nPagesize; u32 ii; /* Read and decode the next journal-header from the journal file. */ rc = sqlite3OsRead(pReal, zBuf, 28, iOff); if( rc!=SQLITE_OK || decodeJournalHdr(zBuf, &nRec, &nPage, &nSector, &nPagesize) ){ goto finish_rjf; } iOff += nSector; if( nRec==0 ){ /* A trick. There might be another journal-header immediately ** following this one. In this case, 0 records means 0 records, ** not "read until the end of the file". See also ticket #2565. */ if( iSize>=(iOff+nSector) ){ rc = sqlite3OsRead(pReal, zBuf, 28, iOff); if( rc!=SQLITE_OK || 0==decodeJournalHdr(zBuf, 0, 0, 0, 0) ){ continue; } } nRec = (iSize-iOff) / (pMain->nPagesize+8); } /* Read all the records that follow the journal-header just read. */ for(ii=0; rc==SQLITE_OK && ii<nRec && iOff<iSize; ii++){ u32 pgno; rc = sqlite3OsRead(pReal, zBuf, 4, iOff); if( rc==SQLITE_OK ){ pgno = decodeUint32(zBuf); if( pgno>0 && pgno<=pMain->nPage ){ if( 0==sqlite3BitvecTest(pMain->pWritable, pgno) ){ rc = sqlite3OsRead(pReal, aPage, pMain->nPagesize, iOff+4); if( rc==SQLITE_OK ){ u32 cksum = genCksum(aPage, pMain->nPagesize); assert( cksum==pMain->aCksum[pgno-1] ); } } sqlite3BitvecSet(pMain->pWritable, pgno); } iOff += (8 + pMain->nPagesize); } } iOff = ((iOff + (nSector-1)) / nSector) * nSector; } finish_rjf: start_ioerr_simulation(iSave, iSave2); sqlite3_free(aPage); if( rc==SQLITE_IOERR_SHORT_READ ){ rc = SQLITE_OK; } return rc; }
/* ** This routine runs an extensive test of the Bitvec code. ** ** The input is an array of integers that acts as a program ** to test the Bitvec. The integers are opcodes followed ** by 0, 1, or 3 operands, depending on the opcode. Another ** opcode follows immediately after the last operand. ** ** There are 6 opcodes numbered from 0 through 5. 0 is the ** "halt" opcode and causes the test to end. ** ** 0 Halt and return the number of errors ** 1 N S X Set N bits beginning with S and incrementing by X ** 2 N S X Clear N bits beginning with S and incrementing by X ** 3 N Set N randomly chosen bits ** 4 N Clear N randomly chosen bits ** 5 N S X Set N bits from S increment X in array only, not in bitvec ** ** The opcodes 1 through 4 perform set and clear operations are performed ** on both a Bitvec object and on a linear array of bits obtained from malloc. ** Opcode 5 works on the linear array only, not on the Bitvec. ** Opcode 5 is used to deliberately induce a fault in order to ** confirm that error detection works. ** ** At the conclusion of the test the linear array is compared ** against the Bitvec object. If there are any differences, ** an error is returned. If they are the same, zero is returned. ** ** If a memory allocation error occurs, return -1. */ int sqlite3BitvecBuiltinTest(int sz, int *aOp){ Bitvec *pBitvec = 0; unsigned char *pV = 0; int rc = -1; int i, nx, pc, op; void *pTmpSpace; /* Allocate the Bitvec to be tested and a linear array of ** bits to act as the reference */ pBitvec = sqlite3BitvecCreate( sz ); pV = sqlite3MallocZero( (sz+7)/8 + 1 ); pTmpSpace = sqlite3_malloc(BITVEC_SZ); if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end; /* NULL pBitvec tests */ sqlite3BitvecSet(0, 1); sqlite3BitvecClear(0, 1, pTmpSpace); /* Run the program */ pc = 0; while( (op = aOp[pc])!=0 ){ switch( op ){ case 1: case 2: case 5: { nx = 4; i = aOp[pc+2] - 1; aOp[pc+2] += aOp[pc+3]; break; } case 3: case 4: default: { nx = 2; sqlite3_randomness(sizeof(i), &i); break; } } if( (--aOp[pc+1]) > 0 ) nx = 0; pc += nx; i = (i & 0x7fffffff)%sz; if( (op & 1)!=0 ){ SETBIT(pV, (i+1)); if( op!=5 ){ if( sqlite3BitvecSet(pBitvec, i+1) ) goto bitvec_end; } }else{ CLEARBIT(pV, (i+1)); sqlite3BitvecClear(pBitvec, i+1, pTmpSpace); } } /* Test to make sure the linear array exactly matches the ** Bitvec object. Start with the assumption that they do ** match (rc==0). Change rc to non-zero if a discrepancy ** is found. */ rc = sqlite3BitvecTest(0,0) + sqlite3BitvecTest(pBitvec, sz+1) + sqlite3BitvecTest(pBitvec, 0) + (sqlite3BitvecSize(pBitvec) - sz); for(i=1; i<=sz; i++){ if( (TESTBIT(pV,i))!=sqlite3BitvecTest(pBitvec,i) ){ rc = i; break; } } /* Free allocated structure */ bitvec_end: sqlite3_free(pTmpSpace); sqlite3_free(pV); sqlite3BitvecDestroy(pBitvec); return rc; }
static int readJournalFile(jt_file *p, jt_file *pMain){ int rc = SQLITE_OK; unsigned char zBuf[28]; sqlite3_file *pReal = p->pReal; sqlite3_int64 iOff = 0; sqlite3_int64 iSize = p->iMaxOff; unsigned char *aPage; int iSave; int iSave2; aPage = sqlite3_malloc(pMain->nPagesize); if( !aPage ){ return SQLITE_IOERR_NOMEM; } stop_ioerr_simulation(&iSave, &iSave2); while( rc==SQLITE_OK && iOff<iSize ){ u32 nRec, nPage, nSector, nPagesize; u32 ii; rc = sqlite3OsRead(pReal, zBuf, 28, iOff); if( rc!=SQLITE_OK || decodeJournalHdr(zBuf, &nRec, &nPage, &nSector, &nPagesize) ){ goto finish_rjf; } iOff += nSector; if( nRec==0 ){ if( iSize>=(iOff+nSector) ){ rc = sqlite3OsRead(pReal, zBuf, 28, iOff); if( rc!=SQLITE_OK || 0==decodeJournalHdr(zBuf, 0, 0, 0, 0) ){ continue; } } nRec = (iSize-iOff) / (pMain->nPagesize+8); } for(ii=0; rc==SQLITE_OK && ii<nRec && iOff<iSize; ii++){ u32 pgno; rc = sqlite3OsRead(pReal, zBuf, 4, iOff); if( rc==SQLITE_OK ){ pgno = decodeUint32(zBuf); if( pgno>0 && pgno<=pMain->nPage ){ if( 0==sqlite3BitvecTest(pMain->pWritable, pgno) ){ rc = sqlite3OsRead(pReal, aPage, pMain->nPagesize, iOff+4); if( rc==SQLITE_OK ){ u32 cksum = genCksum(aPage, pMain->nPagesize); assert( cksum==pMain->aCksum[pgno-1] ); } } sqlite3BitvecSet(pMain->pWritable, pgno); } iOff += (8 + pMain->nPagesize); } } iOff = ((iOff + (nSector-1)) / nSector) * nSector; } finish_rjf: start_ioerr_simulation(iSave, iSave2); sqlite3_free(aPage); if( rc==SQLITE_IOERR_SHORT_READ ){ rc = SQLITE_OK; } return rc; }