aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2005-11-26 00:25:00 +0000
committerdrh <drh@noemail.net>2005-11-26 00:25:00 +0000
commit9c06c95309ab7730db6442a0e192a8a86b3a0fac (patch)
tree297e22bca6307b037d8f709058fad465fdd4b2db /src
parentaa2289f89c9def1a983b6c557285c057186ffbc7 (diff)
downloadsqlite-9c06c95309ab7730db6442a0e192a8a86b3a0fac.tar.gz
sqlite-9c06c95309ab7730db6442a0e192a8a86b3a0fac.zip
Modify the OS layer so that I/O routines are called through a virtual function
table. The os_test.c module has been replaced by test6.c. The crash tests are busted now and need to be fixed. (CVS 2785) FossilOrigin-Name: 1f69aec285dd8e26bd739d5e44bb50fe03a9682a
Diffstat (limited to 'src')
-rw-r--r--src/os.h49
-rw-r--r--src/os_unix.c73
-rw-r--r--src/os_win.c70
-rw-r--r--src/pager.c189
-rw-r--r--src/pragma.c4
-rw-r--r--src/tclsqlite.c4
-rw-r--r--src/test1.c42
-rw-r--r--src/test2.c10
-rw-r--r--src/test6.c478
-rw-r--r--src/vacuum.c6
-rw-r--r--src/vdbe.c4
-rw-r--r--src/vdbeaux.c32
12 files changed, 738 insertions, 223 deletions
diff --git a/src/os.h b/src/os.h
index a161d134a..364630877 100644
--- a/src/os.h
+++ b/src/os.h
@@ -172,28 +172,32 @@ extern unsigned int sqlite3_pending_byte;
#define SHARED_FIRST (PENDING_BYTE+2)
#define SHARED_SIZE 510
-
-int sqlite3OsDelete(const char*);
-int sqlite3OsFileExists(const char*);
-int sqlite3OsOpenReadWrite(const char*, OsFile*, int*);
-int sqlite3OsOpenExclusive(const char*, OsFile*, int);
-int sqlite3OsOpenReadOnly(const char*, OsFile*);
-int sqlite3OsOpenDirectory(const char*, OsFile*);
-int sqlite3OsSyncDirectory(const char*);
-int sqlite3OsTempFileName(char*);
-int sqlite3OsIsDirWritable(char*);
-int sqlite3OsClose(OsFile*);
-int sqlite3OsRead(OsFile*, void*, int amt);
-int sqlite3OsWrite(OsFile*, const void*, int amt);
-int sqlite3OsSeek(OsFile*, i64 offset);
-int sqlite3OsSync(OsFile*, int);
-int sqlite3OsTruncate(OsFile*, i64 size);
-int sqlite3OsFileSize(OsFile*, i64 *pSize);
-char *sqlite3OsFullPathname(const char*);
-int sqlite3OsLock(OsFile*, int);
-int sqlite3OsUnlock(OsFile*, int);
-int sqlite3OsCheckReservedLock(OsFile *id);
-
+/*
+** A single global instance of the following structure holds pointers to the
+** various disk I/O routines.
+*/
+extern struct sqlite3IoVtbl {
+ int (*xDelete)(const char*);
+ int (*xFileExists)(const char*);
+ int (*xOpenReadWrite)(const char*, OsFile*, int*);
+ int (*xOpenExclusive)(const char*, OsFile*, int);
+ int (*xOpenReadOnly)(const char*, OsFile*);
+ int (*xOpenDirectory)(const char*, OsFile*);
+ int (*xSyncDirectory)(const char*);
+ int (*xTempFileName)(char*);
+ int (*xIsDirWritable)(char*);
+ int (*xClose)(OsFile*);
+ int (*xRead)(OsFile*, void*, int amt);
+ int (*xWrite)(OsFile*, const void*, int amt);
+ int (*xSeek)(OsFile*, i64 offset);
+ int (*xSync)(OsFile*, int);
+ int (*xTruncate)(OsFile*, i64 size);
+ int (*xFileSize)(OsFile*, i64 *pSize);
+ char *(*xFullPathname)(const char*);
+ int (*xLock)(OsFile*, int);
+ int (*xUnlock)(OsFile*, int);
+ int (*xCheckReservedLock)(OsFile *id);
+} sqlite3Io;
/* The interface for file I/O is above. Other miscellaneous functions
** are below */
@@ -204,4 +208,5 @@ int sqlite3OsCurrentTime(double*);
void sqlite3OsEnterMutex(void);
void sqlite3OsLeaveMutex(void);
+
#endif /* _SQLITE_OS_H_ */
diff --git a/src/os_unix.c b/src/os_unix.c
index 2d6f40413..33185ed82 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -481,7 +481,7 @@ static int findLockInfo(
/*
** Delete the named file
*/
-int sqlite3OsDelete(const char *zFilename){
+static int unixDelete(const char *zFilename){
unlink(zFilename);
return SQLITE_OK;
}
@@ -489,7 +489,7 @@ int sqlite3OsDelete(const char *zFilename){
/*
** Return TRUE if the named file exists.
*/
-int sqlite3OsFileExists(const char *zFilename){
+static int unixFileExists(const char *zFilename){
return access(zFilename, 0)==0;
}
@@ -506,7 +506,7 @@ int sqlite3OsFileExists(const char *zFilename){
** On failure, the function returns SQLITE_CANTOPEN and leaves
** *id and *pReadonly unchanged.
*/
-int sqlite3OsOpenReadWrite(
+static int unixOpenReadWrite(
const char *zFilename,
OsFile *id,
int *pReadonly
@@ -560,7 +560,7 @@ int sqlite3OsOpenReadWrite(
**
** On failure, return SQLITE_CANTOPEN.
*/
-int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
+static int unixOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
int rc;
assert( !id->isOpen );
if( access(zFilename, 0)==0 ){
@@ -599,7 +599,7 @@ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
**
** On failure, return SQLITE_CANTOPEN.
*/
-int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
+static int unixOpenReadOnly(const char *zFilename, OsFile *id){
int rc;
assert( !id->isOpen );
SET_THREADID(id);
@@ -638,7 +638,7 @@ int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
** On failure, the function returns SQLITE_CANTOPEN and leaves
** *id unchanged.
*/
-int sqlite3OsOpenDirectory(
+static int unixOpenDirectory(
const char *zDirname,
OsFile *id
){
@@ -668,7 +668,7 @@ char *sqlite3_temp_directory = 0;
** Create a temporary file name in zBuf. zBuf must be big enough to
** hold at least SQLITE_TEMPNAME_SIZE characters.
*/
-int sqlite3OsTempFileName(char *zBuf){
+static int unixTempFileName(char *zBuf){
static const char *azDirs[] = {
0,
"/var/tmp",
@@ -704,28 +704,28 @@ int sqlite3OsTempFileName(char *zBuf){
return SQLITE_OK;
}
-#ifndef SQLITE_OMIT_PAGER_PRAGMAS
/*
** Check that a given pathname is a directory and is writable
**
*/
-int sqlite3OsIsDirWritable(char *zBuf){
+static int unixIsDirWritable(char *zBuf){
+#ifndef SQLITE_OMIT_PAGER_PRAGMAS
struct stat buf;
if( zBuf==0 ) return 0;
if( zBuf[0]==0 ) return 0;
if( stat(zBuf, &buf) ) return 0;
if( !S_ISDIR(buf.st_mode) ) return 0;
if( access(zBuf, 07) ) return 0;
+#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
return 1;
}
-#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
/*
** Read data from a file into a buffer. Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
*/
-int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
+static int unixRead(OsFile *id, void *pBuf, int amt){
int got;
assert( id->isOpen );
SimulateIOError(SQLITE_IOERR);
@@ -746,7 +746,7 @@ int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
** Write data from a buffer into a file. Return SQLITE_OK on success
** or some other error code on failure.
*/
-int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
+static int unixWrite(OsFile *id, const void *pBuf, int amt){
int wrote = 0;
assert( id->isOpen );
assert( amt>0 );
@@ -769,7 +769,7 @@ int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
/*
** Move the read/write pointer in a file.
*/
-int sqlite3OsSeek(OsFile *id, i64 offset){
+static int unixSeek(OsFile *id, i64 offset){
assert( id->isOpen );
SEEK(offset/1024 + 1);
#ifdef SQLITE_TEST
@@ -863,7 +863,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
** the directory entry for the journal was never created) and the transaction
** will not roll back - possibly leading to database corruption.
*/
-int sqlite3OsSync(OsFile *id, int dataOnly){
+static int unixSync(OsFile *id, int dataOnly){
assert( id->isOpen );
SimulateIOError(SQLITE_IOERR);
TRACE2("SYNC %-3d\n", id->h);
@@ -891,7 +891,7 @@ int sqlite3OsSync(OsFile *id, int dataOnly){
** before making changes to individual journals on a multi-database commit.
** The F_FULLFSYNC option is not needed here.
*/
-int sqlite3OsSyncDirectory(const char *zDirname){
+static int unixSyncDirectory(const char *zDirname){
#ifdef SQLITE_DISABLE_DIRSYNC
return SQLITE_OK;
#else
@@ -912,7 +912,7 @@ int sqlite3OsSyncDirectory(const char *zDirname){
/*
** Truncate an open file to a specified size
*/
-int sqlite3OsTruncate(OsFile *id, i64 nByte){
+static int unixTruncate(OsFile *id, i64 nByte){
assert( id->isOpen );
SimulateIOError(SQLITE_IOERR);
return ftruncate(id->h, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;
@@ -921,7 +921,7 @@ int sqlite3OsTruncate(OsFile *id, i64 nByte){
/*
** Determine the current size of a file in bytes
*/
-int sqlite3OsFileSize(OsFile *id, i64 *pSize){
+static int unixFileSize(OsFile *id, i64 *pSize){
struct stat buf;
assert( id->isOpen );
SimulateIOError(SQLITE_IOERR);
@@ -938,7 +938,7 @@ int sqlite3OsFileSize(OsFile *id, i64 *pSize){
** non-zero. If the file is unlocked or holds only SHARED locks, then
** return zero.
*/
-int sqlite3OsCheckReservedLock(OsFile *id){
+static int unixCheckReservedLock(OsFile *id){
int r = 0;
assert( id->isOpen );
@@ -1012,7 +1012,7 @@ static const char * locktypeName(int locktype){
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-int sqlite3OsLock(OsFile *id, int locktype){
+static int unixLock(OsFile *id, int locktype){
/* The following describes the implementation of the various locks and
** lock transitions in terms of the POSIX advisory shared and exclusive
** lock primitives (called read-locks and write-locks below, to avoid
@@ -1208,7 +1208,7 @@ end_lock:
** is NO_LOCK. If the second argument is SHARED_LOCK, this routine
** might return SQLITE_IOERR instead of SQLITE_OK.
*/
-int sqlite3OsUnlock(OsFile *id, int locktype){
+static int unixUnlock(OsFile *id, int locktype){
struct lockInfo *pLock;
struct flock lock;
int rc = SQLITE_OK;
@@ -1291,10 +1291,10 @@ int sqlite3OsUnlock(OsFile *id, int locktype){
/*
** Close a file.
*/
-int sqlite3OsClose(OsFile *id){
+static int unixClose(OsFile *id){
if( !id->isOpen ) return SQLITE_OK;
if( CHECK_THREADID(id) ) return SQLITE_MISUSE;
- sqlite3OsUnlock(id, NO_LOCK);
+ sqlite3Io.xUnlock(id, NO_LOCK);
if( id->dirfd>=0 ) close(id->dirfd);
id->dirfd = -1;
sqlite3OsEnterMutex();
@@ -1333,7 +1333,7 @@ int sqlite3OsClose(OsFile *id){
** The calling function is responsible for freeing this space once it
** is no longer needed.
*/
-char *sqlite3OsFullPathname(const char *zRelative){
+static char *unixFullPathname(const char *zRelative){
char *zFull = 0;
if( zRelative[0]=='/' ){
sqlite3SetString(&zFull, zRelative, (char*)0);
@@ -1351,6 +1351,33 @@ char *sqlite3OsFullPathname(const char *zRelative){
}
+/*
+** This is the structure that defines all of the I/O routines.
+*/
+struct sqlite3IoVtbl sqlite3Io = {
+ unixDelete,
+ unixFileExists,
+ unixOpenReadWrite,
+ unixOpenExclusive,
+ unixOpenReadOnly,
+ unixOpenDirectory,
+ unixSyncDirectory,
+ unixTempFileName,
+ unixIsDirWritable,
+ unixClose,
+ unixRead,
+ unixWrite,
+ unixSeek,
+ unixSync,
+ unixTruncate,
+ unixFileSize,
+ unixFullPathname,
+ unixLock,
+ unixUnlock,
+ unixCheckReservedLock,
+};
+
+
#endif /* SQLITE_OMIT_DISKIO */
/***************************************************************************
** Everything above deals with file I/O. Everything that follows deals
diff --git a/src/os_win.c b/src/os_win.c
index ad874ae63..b3715c74f 100644
--- a/src/os_win.c
+++ b/src/os_win.c
@@ -126,7 +126,7 @@ static char *unicodeToUtf8(const WCHAR *zWideFilename){
/*
** Delete the named file
*/
-int sqlite3OsDelete(const char *zFilename){
+static int winDelete(const char *zFilename){
WCHAR *zWide = utf8ToUnicode(zFilename);
if( zWide ){
DeleteFileW(zWide);
@@ -141,7 +141,7 @@ int sqlite3OsDelete(const char *zFilename){
/*
** Return TRUE if the named file exists.
*/
-int sqlite3OsFileExists(const char *zFilename){
+static int winFileExists(const char *zFilename){
int exists = 0;
WCHAR *zWide = utf8ToUnicode(zFilename);
if( zWide ){
@@ -166,7 +166,7 @@ int sqlite3OsFileExists(const char *zFilename){
** On failure, the function returns SQLITE_CANTOPEN and leaves
** *id and *pReadonly unchanged.
*/
-int sqlite3OsOpenReadWrite(
+static int winOpenReadWrite(
const char *zFilename,
OsFile *id,
int *pReadonly
@@ -251,7 +251,7 @@ int sqlite3OsOpenReadWrite(
**
** On failure, return SQLITE_CANTOPEN.
*/
-int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
+static int winOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
HANDLE h;
int fileflags;
WCHAR *zWide = utf8ToUnicode(zFilename);
@@ -301,7 +301,7 @@ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
**
** On failure, return SQLITE_CANTOPEN.
*/
-int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
+static int winOpenReadOnly(const char *zFilename, OsFile *id){
HANDLE h;
WCHAR *zWide = utf8ToUnicode(zFilename);
assert( !id->isOpen );
@@ -353,7 +353,7 @@ int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
** On failure, the function returns SQLITE_CANTOPEN and leaves
** *id unchanged.
*/
-int sqlite3OsOpenDirectory(
+static int winOpenDirectory(
const char *zDirname,
OsFile *id
){
@@ -371,7 +371,7 @@ char *sqlite3_temp_directory = 0;
** Create a temporary file name in zBuf. zBuf must be big enough to
** hold at least SQLITE_TEMPNAME_SIZE characters.
*/
-int sqlite3OsTempFileName(char *zBuf){
+static int winTempFileName(char *zBuf){
static char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@@ -404,7 +404,7 @@ int sqlite3OsTempFileName(char *zBuf){
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
- if( !sqlite3OsFileExists(zBuf) ) break;
+ if( !sqlite3Io.xFileExists(zBuf) ) break;
}
TRACE2("TEMP FILENAME: %s\n", zBuf);
return SQLITE_OK;
@@ -413,7 +413,7 @@ int sqlite3OsTempFileName(char *zBuf){
/*
** Close a file.
*/
-int sqlite3OsClose(OsFile *id){
+static int winClose(OsFile *id){
if( id->isOpen ){
TRACE2("CLOSE %d\n", id->h);
CloseHandle(id->h);
@@ -428,7 +428,7 @@ int sqlite3OsClose(OsFile *id){
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
*/
-int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
+static int winRead(OsFile *id, void *pBuf, int amt){
DWORD got;
assert( id->isOpen );
SimulateIOError(SQLITE_IOERR);
@@ -447,7 +447,7 @@ int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
** Write data from a buffer into a file. Return SQLITE_OK on success
** or some other error code on failure.
*/
-int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
+static int winWrite(OsFile *id, const void *pBuf, int amt){
int rc = 0;
DWORD wrote;
assert( id->isOpen );
@@ -475,7 +475,7 @@ int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
/*
** Move the read/write pointer in a file.
*/
-int sqlite3OsSeek(OsFile *id, i64 offset){
+static int winSeek(OsFile *id, i64 offset){
LONG upperBits = offset>>32;
LONG lowerBits = offset & 0xffffffff;
DWORD rc;
@@ -495,7 +495,7 @@ int sqlite3OsSeek(OsFile *id, i64 offset){
/*
** Make sure all writes to a particular file are committed to disk.
*/
-int sqlite3OsSync(OsFile *id, int dataOnly){
+static int winSync(OsFile *id, int dataOnly){
assert( id->isOpen );
TRACE3("SYNC %d lock=%d\n", id->h, id->locktype);
if( FlushFileBuffers(id->h) ){
@@ -509,7 +509,7 @@ int sqlite3OsSync(OsFile *id, int dataOnly){
** Sync the directory zDirname. This is a no-op on operating systems other
** than UNIX.
*/
-int sqlite3OsSyncDirectory(const char *zDirname){
+static int winSyncDirectory(const char *zDirname){
SimulateIOError(SQLITE_IOERR);
return SQLITE_OK;
}
@@ -517,7 +517,7 @@ int sqlite3OsSyncDirectory(const char *zDirname){
/*
** Truncate an open file to a specified size
*/
-int sqlite3OsTruncate(OsFile *id, i64 nByte){
+static int winTruncate(OsFile *id, i64 nByte){
LONG upperBits = nByte>>32;
assert( id->isOpen );
TRACE3("TRUNCATE %d %lld\n", id->h, nByte);
@@ -530,7 +530,7 @@ int sqlite3OsTruncate(OsFile *id, i64 nByte){
/*
** Determine the current size of a file in bytes
*/
-int sqlite3OsFileSize(OsFile *id, i64 *pSize){
+static int winFileSize(OsFile *id, i64 *pSize){
DWORD upperBits, lowerBits;
assert( id->isOpen );
SimulateIOError(SQLITE_IOERR);
@@ -579,7 +579,7 @@ static int unlockReadLock(OsFile *id){
** Check that a given pathname is a directory and is writable
**
*/
-int sqlite3OsIsDirWritable(char *zDirname){
+static int winIsDirWritable(char *zDirname){
int fileAttr;
WCHAR *zWide;
if( zDirname==0 ) return 0;
@@ -620,12 +620,12 @@ int sqlite3OsIsDirWritable(char *zDirname){
** RESERVED -> (PENDING) -> EXCLUSIVE
** PENDING -> EXCLUSIVE
**
-** This routine will only increase a lock. The sqlite3OsUnlock() routine
+** This routine will only increase a lock. The winUnlock() routine
** erases all locks at once and returns us immediately to locking level 0.
** It is not possible to lower the locking level one step at a time. You
** must go straight to locking level 0.
*/
-int sqlite3OsLock(OsFile *id, int locktype){
+static int winLock(OsFile *id, int locktype){
int rc = SQLITE_OK; /* Return code from subroutines */
int res = 1; /* Result of a windows lock call */
int newLocktype; /* Set id->locktype to this value before exiting */
@@ -735,7 +735,7 @@ int sqlite3OsLock(OsFile *id, int locktype){
** file by this or any other process. If such a lock is held, return
** non-zero, otherwise zero.
*/
-int sqlite3OsCheckReservedLock(OsFile *id){
+static int winCheckReservedLock(OsFile *id){
int rc;
assert( id->isOpen );
if( id->locktype>=RESERVED_LOCK ){
@@ -763,7 +763,7 @@ int sqlite3OsCheckReservedLock(OsFile *id){
** is NO_LOCK. If the second argument is SHARED_LOCK then this routine
** might return SQLITE_IOERR;
*/
-int sqlite3OsUnlock(OsFile *id, int locktype){
+static int winUnlock(OsFile *id, int locktype){
int type;
int rc = SQLITE_OK;
assert( id->isOpen );
@@ -798,7 +798,7 @@ int sqlite3OsUnlock(OsFile *id, int locktype){
** The calling function is responsible for freeing this space once it
** is no longer needed.
*/
-char *sqlite3OsFullPathname(const char *zRelative){
+static char *winFullPathname(const char *zRelative){
char *zNotUsed;
char *zFull;
WCHAR *zWide;
@@ -829,6 +829,32 @@ char *sqlite3OsFullPathname(const char *zRelative){
return zFull;
}
+/*
+** This is the structure that defines all of the I/O routines.
+*/
+struct sqlite3IoVtbl sqlite3Io = {
+ winDelete,
+ winFileExists,
+ winOpenReadWrite,
+ winOpenExclusive,
+ winOpenReadOnly,
+ winOpenDirectory,
+ winSyncDirectory,
+ winTempFileName,
+ winIsDirWritable,
+ winClose,
+ winRead,
+ winWrite,
+ winSeek,
+ winSync,
+ winTruncate,
+ winFileSize,
+ winFullPathname,
+ winLock,
+ winUnlock,
+ winCheckReservedLock,
+};
+
#endif /* SQLITE_OMIT_DISKIO */
/***************************************************************************
** Everything above deals with file I/O. Everything that follows deals
diff --git a/src/pager.c b/src/pager.c
index 58918bbdb..07e728d80 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while
** another is writing.
**
-** @(#) $Id: pager.c,v 1.217 2005/11/05 15:11:23 drh Exp $
+** @(#) $Id: pager.c,v 1.218 2005/11/26 00:25:03 drh Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
@@ -413,7 +413,7 @@ static const unsigned char aJournalMagic[] = {
static int read32bits(OsFile *fd, u32 *pRes){
u32 res;
int rc;
- rc = sqlite3OsRead(fd, &res, sizeof(res));
+ rc = sqlite3Io.xRead(fd, &res, sizeof(res));
if( rc==SQLITE_OK ){
unsigned char ac[4];
memcpy(ac, &res, 4);
@@ -433,7 +433,7 @@ static int write32bits(OsFile *fd, u32 val){
ac[1] = (val>>16) & 0xff;
ac[2] = (val>>8) & 0xff;
ac[3] = val & 0xff;
- return sqlite3OsWrite(fd, ac, 4);
+ return sqlite3Io.xWrite(fd, ac, 4);
}
/*
@@ -524,10 +524,10 @@ static int readMasterJournal(OsFile *pJrnl, char **pzMaster){
*pzMaster = 0;
- rc = sqlite3OsFileSize(pJrnl, &szJ);
+ rc = sqlite3Io.xFileSize(pJrnl, &szJ);
if( rc!=SQLITE_OK || szJ<16 ) return rc;
- rc = sqlite3OsSeek(pJrnl, szJ-16);
+ rc = sqlite3Io.xSeek(pJrnl, szJ-16);
if( rc!=SQLITE_OK ) return rc;
rc = read32bits(pJrnl, &len);
@@ -536,17 +536,17 @@ static int readMasterJournal(OsFile *pJrnl, char **pzMaster){
rc = read32bits(pJrnl, &cksum);
if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3OsRead(pJrnl, aMagic, 8);
+ rc = sqlite3Io.xRead(pJrnl, aMagic, 8);
if( rc!=SQLITE_OK || memcmp(aMagic, aJournalMagic, 8) ) return rc;
- rc = sqlite3OsSeek(pJrnl, szJ-16-len);
+ rc = sqlite3Io.xSeek(pJrnl, szJ-16-len);
if( rc!=SQLITE_OK ) return rc;
*pzMaster = (char *)sqliteMalloc(len+1);
if( !*pzMaster ){
return SQLITE_NOMEM;
}
- rc = sqlite3OsRead(pJrnl, *pzMaster, len);
+ rc = sqlite3Io.xRead(pJrnl, *pzMaster, len);
if( rc!=SQLITE_OK ){
sqliteFree(*pzMaster);
*pzMaster = 0;
@@ -597,7 +597,7 @@ static int seekJournalHdr(Pager *pPager){
assert( offset>=c );
assert( (offset-c)<JOURNAL_HDR_SZ(pPager) );
pPager->journalOff = offset;
- return sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
+ return sqlite3Io.xSeek(&pPager->jfd, pPager->journalOff);
}
/*
@@ -633,7 +633,7 @@ static int writeJournalHdr(Pager *pPager){
** Actually maybe the whole journal header should be delayed until that
** point. Think about this.
*/
- rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));
+ rc = sqlite3Io.xWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));
if( rc==SQLITE_OK ){
/* The nRec Field. 0xFFFFFFFF for no-sync journals. */
@@ -657,9 +657,9 @@ static int writeJournalHdr(Pager *pPager){
** file descriptor to the end of the journal header sector.
*/
if( rc==SQLITE_OK ){
- rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff-1);
+ rc = sqlite3Io.xSeek(&pPager->jfd, pPager->journalOff-1);
if( rc==SQLITE_OK ){
- rc = sqlite3OsWrite(&pPager->jfd, "\000", 1);
+ rc = sqlite3Io.xWrite(&pPager->jfd, "\000", 1);
}
}
return rc;
@@ -697,7 +697,7 @@ static int readJournalHdr(
return SQLITE_DONE;
}
- rc = sqlite3OsRead(&pPager->jfd, aMagic, sizeof(aMagic));
+ rc = sqlite3Io.xRead(&pPager->jfd, aMagic, sizeof(aMagic));
if( rc ) return rc;
if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){
@@ -723,7 +723,7 @@ static int readJournalHdr(
if( rc ) return rc;
pPager->journalOff += JOURNAL_HDR_SZ(pPager);
- rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
+ rc = sqlite3Io.xSeek(&pPager->jfd, pPager->journalOff);
return rc;
}
@@ -771,7 +771,7 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
rc = write32bits(&pPager->jfd, PAGER_MJ_PGNO(pPager));
if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3OsWrite(&pPager->jfd, zMaster, len);
+ rc = sqlite3Io.xWrite(&pPager->jfd, zMaster, len);
if( rc!=SQLITE_OK ) return rc;
rc = write32bits(&pPager->jfd, len);
@@ -780,7 +780,7 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
rc = write32bits(&pPager->jfd, cksum);
if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));
+ rc = sqlite3Io.xWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));
pPager->needSync = !pPager->noSync;
return rc;
}
@@ -858,7 +858,7 @@ static void pager_reset(Pager *pPager){
if( pPager->state>=PAGER_RESERVED ){
sqlite3pager_rollback(pPager);
}
- sqlite3OsUnlock(&pPager->fd, NO_LOCK);
+ sqlite3Io.xUnlock(&pPager->fd, NO_LOCK);
pPager->state = PAGER_UNLOCK;
pPager->dbSize = -1;
pPager->nRef = 0;
@@ -907,13 +907,13 @@ static int pager_unwritelock(Pager *pPager){
}
sqlite3pager_stmt_commit(pPager);
if( pPager->stmtOpen ){
- sqlite3OsClose(&pPager->stfd);
+ sqlite3Io.xClose(&pPager->stfd);
pPager->stmtOpen = 0;
}
if( pPager->journalOpen ){
- sqlite3OsClose(&pPager->jfd);
+ sqlite3Io.xClose(&pPager->jfd);
pPager->journalOpen = 0;
- sqlite3OsDelete(pPager->zJournal);
+ sqlite3Io.xDelete(pPager->zJournal);
sqliteFree( pPager->aInJournal );
pPager->aInJournal = 0;
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
@@ -930,7 +930,7 @@ static int pager_unwritelock(Pager *pPager){
assert( pPager->aInJournal==0 );
assert( pPager->dirtyCache==0 || pPager->useJournal==0 );
}
- rc = sqlite3OsUnlock(&pPager->fd, SHARED_LOCK);
+ rc = sqlite3Io.xUnlock(&pPager->fd, SHARED_LOCK);
pPager->state = PAGER_SHARED;
pPager->origDbSize = 0;
pPager->setMaster = 0;
@@ -990,7 +990,7 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
rc = read32bits(jfd, &pgno);
if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3OsRead(jfd, &aData, pPager->pageSize);
+ rc = sqlite3Io.xRead(jfd, &aData, pPager->pageSize);
if( rc!=SQLITE_OK ) return rc;
pPager->journalOff += pPager->pageSize + 4;
@@ -1040,9 +1040,9 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 );
TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno);
if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){
- rc = sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
+ rc = sqlite3Io.xSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
if( rc==SQLITE_OK ){
- rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize);
+ rc = sqlite3Io.xWrite(&pPager->fd, aData, pPager->pageSize);
}
if( pPg ) pPg->dirty = 0;
}
@@ -1090,10 +1090,10 @@ static int pager_delmaster(const char *zMaster){
** is running this routine also. Not that it makes too much difference.
*/
memset(&master, 0, sizeof(master));
- rc = sqlite3OsOpenReadOnly(zMaster, &master);
+ rc = sqlite3Io.xOpenReadOnly(zMaster, &master);
if( rc!=SQLITE_OK ) goto delmaster_out;
master_open = 1;
- rc = sqlite3OsFileSize(&master, &nMasterJournal);
+ rc = sqlite3Io.xFileSize(&master, &nMasterJournal);
if( rc!=SQLITE_OK ) goto delmaster_out;
if( nMasterJournal>0 ){
@@ -1108,12 +1108,12 @@ static int pager_delmaster(const char *zMaster){
rc = SQLITE_NOMEM;
goto delmaster_out;
}
- rc = sqlite3OsRead(&master, zMasterJournal, nMasterJournal);
+ rc = sqlite3Io.xRead(&master, zMasterJournal, nMasterJournal);
if( rc!=SQLITE_OK ) goto delmaster_out;
zJournal = zMasterJournal;
while( (zJournal-zMasterJournal)<nMasterJournal ){
- if( sqlite3OsFileExists(zJournal) ){
+ if( sqlite3Io.xFileExists(zJournal) ){
/* One of the journals pointed to by the master journal exists.
** Open it and check if it points at the master journal. If
** so, return without deleting the master journal file.
@@ -1122,13 +1122,13 @@ static int pager_delmaster(const char *zMaster){
int c;
memset(&journal, 0, sizeof(journal));
- rc = sqlite3OsOpenReadOnly(zJournal, &journal);
+ rc = sqlite3Io.xOpenReadOnly(zJournal, &journal);
if( rc!=SQLITE_OK ){
goto delmaster_out;
}
rc = readMasterJournal(&journal, &zMasterPtr);
- sqlite3OsClose(&journal);
+ sqlite3Io.xClose(&journal);
if( rc!=SQLITE_OK ){
goto delmaster_out;
}
@@ -1144,14 +1144,14 @@ static int pager_delmaster(const char *zMaster){
}
}
- sqlite3OsDelete(zMaster);
+ sqlite3Io.xDelete(zMaster);
delmaster_out:
if( zMasterJournal ){
sqliteFree(zMasterJournal);
}
if( master_open ){
- sqlite3OsClose(&master);
+ sqlite3Io.xClose(&master);
}
return rc;
}
@@ -1172,9 +1172,9 @@ static int pager_reload_cache(Pager *pPager){
char zBuf[SQLITE_MAX_PAGE_SIZE];
if( !pPg->dirty ) continue;
if( (int)pPg->pgno <= pPager->origDbSize ){
- rc = sqlite3OsSeek(&pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1));
+ rc = sqlite3Io.xSeek(&pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1));
if( rc==SQLITE_OK ){
- rc = sqlite3OsRead(&pPager->fd, zBuf, pPager->pageSize);
+ rc = sqlite3Io.xRead(&pPager->fd, zBuf, pPager->pageSize);
}
TRACE3("REFETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
if( rc ) break;
@@ -1205,7 +1205,7 @@ static int pager_reload_cache(Pager *pPager){
*/
static int pager_truncate(Pager *pPager, int nPage){
assert( pPager->state>=PAGER_EXCLUSIVE );
- return sqlite3OsTruncate(&pPager->fd, pPager->pageSize*(i64)nPage);
+ return sqlite3Io.xTruncate(&pPager->fd, pPager->pageSize*(i64)nPage);
}
/*
@@ -1273,7 +1273,7 @@ static int pager_playback(Pager *pPager){
** the journal is empty.
*/
assert( pPager->journalOpen );
- rc = sqlite3OsFileSize(&pPager->jfd, &szJ);
+ rc = sqlite3Io.xFileSize(&pPager->jfd, &szJ);
if( rc!=SQLITE_OK ){
goto end_playback;
}
@@ -1285,13 +1285,13 @@ static int pager_playback(Pager *pPager){
*/
rc = readMasterJournal(&pPager->jfd, &zMaster);
assert( rc!=SQLITE_DONE );
- if( rc!=SQLITE_OK || (zMaster && !sqlite3OsFileExists(zMaster)) ){
+ if( rc!=SQLITE_OK || (zMaster && !sqlite3Io.xFileExists(zMaster)) ){
sqliteFree(zMaster);
zMaster = 0;
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
goto end_playback;
}
- sqlite3OsSeek(&pPager->jfd, 0);
+ sqlite3Io.xSeek(&pPager->jfd, 0);
pPager->journalOff = 0;
/* This loop terminates either when the readJournalHdr() call returns
@@ -1334,7 +1334,7 @@ static int pager_playback(Pager *pPager){
pPager->dbSize = mxPg;
}
- /* rc = sqlite3OsSeek(&pPager->jfd, JOURNAL_HDR_SZ(pPager)); */
+ /* rc = sqlite3Io.xSeek(&pPager->jfd, JOURNAL_HDR_SZ(pPager)); */
if( rc!=SQLITE_OK ) goto end_playback;
/* Copy original pages out of the journal and back into the database file.
@@ -1407,7 +1407,7 @@ static int pager_stmt_playback(Pager *pPager){
#ifndef NDEBUG
{
i64 os_szJ;
- rc = sqlite3OsFileSize(&pPager->jfd, &os_szJ);
+ rc = sqlite3Io.xFileSize(&pPager->jfd, &os_szJ);
if( rc!=SQLITE_OK ) return rc;
assert( szJ==os_szJ );
}
@@ -1433,7 +1433,7 @@ static int pager_stmt_playback(Pager *pPager){
/* Figure out how many records are in the statement journal.
*/
assert( pPager->stmtInUse && pPager->journalOpen );
- sqlite3OsSeek(&pPager->stfd, 0);
+ sqlite3Io.xSeek(&pPager->stfd, 0);
nRec = pPager->stmtNRec;
/* Copy original pages out of the statement journal and back into the
@@ -1455,7 +1455,7 @@ static int pager_stmt_playback(Pager *pPager){
** If it is not zero, then Pager.stmtHdrOff is the offset to the start
** of the first journal header written during this statement transaction.
*/
- rc = sqlite3OsSeek(&pPager->jfd, pPager->stmtJSize);
+ rc = sqlite3Io.xSeek(&pPager->jfd, pPager->stmtJSize);
if( rc!=SQLITE_OK ){
goto end_stmt_playback;
}
@@ -1515,7 +1515,7 @@ void sqlite3pager_set_cachesize(Pager *pPager, int mxPage){
** or power failures by changing the number of syncs()s when writing
** the rollback journal. There are three levels:
**
-** OFF sqlite3OsSync() is never called. This is the default
+** OFF sqlite3Io.xSync() is never called. This is the default
** for temporary and transient files.
**
** NORMAL The journal is synced once before writes begin on the
@@ -1566,8 +1566,8 @@ static int sqlite3pager_opentemp(char *zFile, OsFile *fd){
sqlite3_opentemp_count++; /* Used for testing and analysis only */
do{
cnt--;
- sqlite3OsTempFileName(zFile);
- rc = sqlite3OsOpenExclusive(zFile, fd, 1);
+ sqlite3Io.xTempFileName(zFile);
+ rc = sqlite3Io.xOpenExclusive(zFile, fd, 1);
}while( cnt>0 && rc!=SQLITE_OK && rc!=SQLITE_NOMEM );
return rc;
}
@@ -1619,32 +1619,32 @@ int sqlite3pager_open(
}else
#endif
{
- zFullPathname = sqlite3OsFullPathname(zFilename);
+ zFullPathname = sqlite3Io.xFullPathname(zFilename);
if( zFullPathname ){
- rc = sqlite3OsOpenReadWrite(zFullPathname, &fd, &readOnly);
+ rc = sqlite3Io.xOpenReadWrite(zFullPathname, &fd, &readOnly);
}
}
}else{
rc = sqlite3pager_opentemp(zTemp, &fd);
zFilename = zTemp;
- zFullPathname = sqlite3OsFullPathname(zFilename);
+ zFullPathname = sqlite3Io.xFullPathname(zFilename);
if( rc==SQLITE_OK ){
tempFile = 1;
}
}
if( !zFullPathname ){
- sqlite3OsClose(&fd);
+ sqlite3Io.xClose(&fd);
return SQLITE_NOMEM;
}
if( rc!=SQLITE_OK ){
- sqlite3OsClose(&fd);
+ sqlite3Io.xClose(&fd);
sqliteFree(zFullPathname);
return rc;
}
nameLen = strlen(zFullPathname);
pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 );
if( pPager==0 ){
- sqlite3OsClose(&fd);
+ sqlite3Io.xClose(&fd);
sqliteFree(zFullPathname);
return SQLITE_NOMEM;
}
@@ -1660,9 +1660,6 @@ int sqlite3pager_open(
sqliteFree(zFullPathname);
strcpy(&pPager->zJournal[nameLen], "-journal");
pPager->fd = fd;
-#if OS_UNIX
- pPager->fd.pPager = pPager;
-#endif
pPager->journalOpen = 0;
pPager->useJournal = useJournal && !memDb;
pPager->noReadlock = noReadlock && readOnly;
@@ -1773,8 +1770,8 @@ void enable_simulated_io_errors(void){
void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
memset(pDest, 0, N);
if( MEMDB==0 ){
- sqlite3OsSeek(&pPager->fd, 0);
- sqlite3OsRead(&pPager->fd, pDest, N);
+ sqlite3Io.xSeek(&pPager->fd, 0);
+ sqlite3Io.xRead(&pPager->fd, pDest, N);
clear_simulated_io_error();
}
}
@@ -1794,7 +1791,7 @@ int sqlite3pager_pagecount(Pager *pPager){
if( pPager->dbSize>=0 ){
n = pPager->dbSize;
} else {
- if( sqlite3OsFileSize(&pPager->fd, &n)!=SQLITE_OK ){
+ if( sqlite3Io.xFileSize(&pPager->fd, &n)!=SQLITE_OK ){
pPager->errMask |= PAGER_ERR_DISK;
return 0;
}
@@ -1926,7 +1923,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
rc = SQLITE_OK;
}else{
do {
- rc = sqlite3OsLock(&pPager->fd, locktype);
+ rc = sqlite3Io.xLock(&pPager->fd, locktype);
}while( rc==SQLITE_BUSY && sqlite3InvokeBusyHandler(pPager->pBusyHandler) );
if( rc==SQLITE_OK ){
pPager->state = locktype;
@@ -1994,14 +1991,14 @@ int sqlite3pager_close(Pager *pPager){
sqlite3pager_rollback(pPager);
enable_simulated_io_errors();
if( !MEMDB ){
- sqlite3OsUnlock(&pPager->fd, NO_LOCK);
+ sqlite3Io.xUnlock(&pPager->fd, NO_LOCK);
}
assert( pPager->errMask || pPager->journalOpen==0 );
break;
}
case PAGER_SHARED: {
if( !MEMDB ){
- sqlite3OsUnlock(&pPager->fd, NO_LOCK);
+ sqlite3Io.xUnlock(&pPager->fd, NO_LOCK);
}
break;
}
@@ -2025,16 +2022,16 @@ int sqlite3pager_close(Pager *pPager){
TRACE2("CLOSE %d\n", PAGERID(pPager));
assert( pPager->errMask || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
if( pPager->journalOpen ){
- sqlite3OsClose(&pPager->jfd);
+ sqlite3Io.xClose(&pPager->jfd);
}
sqliteFree(pPager->aInJournal);
if( pPager->stmtOpen ){
- sqlite3OsClose(&pPager->stfd);
+ sqlite3Io.xClose(&pPager->stfd);
}
- sqlite3OsClose(&pPager->fd);
+ sqlite3Io.xClose(&pPager->fd);
/* Temp files are automatically deleted by the OS
** if( pPager->tempFile ){
- ** sqlite3OsDelete(pPager->zFilename);
+ ** sqlite3Io.xDelete(pPager->zFilename);
** }
*/
@@ -2143,7 +2140,7 @@ static int syncJournal(Pager *pPager){
** with the nRec computed from the size of the journal file.
*/
i64 jSz;
- rc = sqlite3OsFileSize(&pPager->jfd, &jSz);
+ rc = sqlite3Io.xFileSize(&pPager->jfd, &jSz);
if( rc!=0 ) return rc;
assert( pPager->journalOff==jSz );
}
@@ -2156,20 +2153,20 @@ static int syncJournal(Pager *pPager){
*/
if( pPager->fullSync ){
TRACE2("SYNC journal of %d\n", PAGERID(pPager));
- rc = sqlite3OsSync(&pPager->jfd, 0);
+ rc = sqlite3Io.xSync(&pPager->jfd, 0);
if( rc!=0 ) return rc;
}
- rc = sqlite3OsSeek(&pPager->jfd,
+ rc = sqlite3Io.xSeek(&pPager->jfd,
pPager->journalHdr + sizeof(aJournalMagic));
if( rc ) return rc;
rc = write32bits(&pPager->jfd, pPager->nRec);
if( rc ) return rc;
- rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
+ rc = sqlite3Io.xSeek(&pPager->jfd, pPager->journalOff);
if( rc ) return rc;
}
TRACE2("SYNC journal of %d\n", PAGERID(pPager));
- rc = sqlite3OsSync(&pPager->jfd, pPager->fullSync);
+ rc = sqlite3Io.xSync(&pPager->jfd, pPager->fullSync);
if( rc!=0 ) return rc;
pPager->journalStarted = 1;
}
@@ -2213,7 +2210,7 @@ static int pager_write_pagelist(PgHdr *pList){
/* At this point there may be either a RESERVED or EXCLUSIVE lock on the
** database file. If there is already an EXCLUSIVE lock, the following
- ** calls to sqlite3OsLock() are no-ops.
+ ** calls to sqlite3Io.xLock() are no-ops.
**
** Moving the lock from RESERVED to EXCLUSIVE actually involves going
** through an intermediate state PENDING. A PENDING lock prevents new
@@ -2234,7 +2231,7 @@ static int pager_write_pagelist(PgHdr *pList){
while( pList ){
assert( pList->dirty );
- rc = sqlite3OsSeek(&pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize);
+ rc = sqlite3Io.xSeek(&pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize);
if( rc ) return rc;
/* If there are dirty pages in the page cache with page numbers greater
** than Pager.dbSize, this means sqlite3pager_truncate() was called to
@@ -2244,7 +2241,8 @@ static int pager_write_pagelist(PgHdr *pList){
if( pList->pgno<=pPager->dbSize ){
CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
TRACE3("STORE %d page %d\n", PAGERID(pPager), pList->pgno);
- rc = sqlite3OsWrite(&pPager->fd, PGHDR_TO_DATA(pList), pPager->pageSize);
+ rc = sqlite3Io.xWrite(&pPager->fd, PGHDR_TO_DATA(pList),
+ pPager->pageSize);
CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0);
TEST_INCR(pPager->nWrite);
}
@@ -2290,10 +2288,10 @@ static PgHdr *pager_get_all_dirty_pages(Pager *pPager){
*/
static int hasHotJournal(Pager *pPager){
if( !pPager->useJournal ) return 0;
- if( !sqlite3OsFileExists(pPager->zJournal) ) return 0;
- if( sqlite3OsCheckReservedLock(&pPager->fd) ) return 0;
+ if( !sqlite3Io.xFileExists(pPager->zJournal) ) return 0;
+ if( sqlite3Io.xCheckReservedLock(&pPager->fd) ) return 0;
if( sqlite3pager_pagecount(pPager)==0 ){
- sqlite3OsDelete(pPager->zJournal);
+ sqlite3Io.xDelete(pPager->zJournal);
return 0;
}else{
return 1;
@@ -2370,9 +2368,9 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
** second process will get to this point in the code and fail to
** obtain it's own EXCLUSIVE lock on the database file.
*/
- rc = sqlite3OsLock(&pPager->fd, EXCLUSIVE_LOCK);
+ rc = sqlite3Io.xLock(&pPager->fd, EXCLUSIVE_LOCK);
if( rc!=SQLITE_OK ){
- sqlite3OsUnlock(&pPager->fd, NO_LOCK);
+ sqlite3Io.xUnlock(&pPager->fd, NO_LOCK);
pPager->state = PAGER_UNLOCK;
return rc;
}
@@ -2386,9 +2384,9 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
** a write lock, so there is never any chance of two or more
** processes opening the journal at the same time.
*/
- rc = sqlite3OsOpenReadOnly(pPager->zJournal, &pPager->jfd);
+ rc = sqlite3Io.xOpenReadOnly(pPager->zJournal, &pPager->jfd);
if( rc!=SQLITE_OK ){
- sqlite3OsUnlock(&pPager->fd, NO_LOCK);
+ sqlite3Io.xUnlock(&pPager->fd, NO_LOCK);
pPager->state = PAGER_UNLOCK;
return SQLITE_BUSY;
}
@@ -2545,15 +2543,16 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
}else{
int rc;
assert( MEMDB==0 );
- rc = sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
+ rc = sqlite3Io.xSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
if( rc==SQLITE_OK ){
- rc = sqlite3OsRead(&pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize);
+ rc = sqlite3Io.xRead(&pPager->fd, PGHDR_TO_DATA(pPg),
+ pPager->pageSize);
}
TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
if( rc!=SQLITE_OK ){
i64 fileSize;
- if( sqlite3OsFileSize(&pPager->fd,&fileSize)!=SQLITE_OK
+ if( sqlite3Io.xFileSize(&pPager->fd,&fileSize)!=SQLITE_OK
|| fileSize>=pgno*pPager->pageSize ){
sqlite3pager_unref(PGHDR_TO_DATA(pPg));
return rc;
@@ -2675,7 +2674,8 @@ static int pager_open_journal(Pager *pPager){
rc = SQLITE_NOMEM;
goto failed_to_open_journal;
}
- rc = sqlite3OsOpenExclusive(pPager->zJournal, &pPager->jfd,pPager->tempFile);
+ rc = sqlite3Io.xOpenExclusive(pPager->zJournal, &pPager->jfd,
+ pPager->tempFile);
pPager->journalOff = 0;
pPager->setMaster = 0;
pPager->journalHdr = 0;
@@ -2684,7 +2684,7 @@ static int pager_open_journal(Pager *pPager){
}
SET_FULLSYNC(pPager->jfd, pPager->fullSync);
SET_FULLSYNC(pPager->fd, pPager->fullSync);
- sqlite3OsOpenDirectory(pPager->zDirectory, &pPager->jfd);
+ sqlite3Io.xOpenDirectory(pPager->zDirectory, &pPager->jfd);
pPager->journalOpen = 1;
pPager->journalStarted = 0;
pPager->needSync = 0;
@@ -2712,7 +2712,7 @@ static int pager_open_journal(Pager *pPager){
failed_to_open_journal:
sqliteFree(pPager->aInJournal);
pPager->aInJournal = 0;
- sqlite3OsUnlock(&pPager->fd, NO_LOCK);
+ sqlite3Io.xUnlock(&pPager->fd, NO_LOCK);
pPager->state = PAGER_UNLOCK;
return rc;
}
@@ -2756,7 +2756,7 @@ int sqlite3pager_begin(void *pData, int exFlag){
pPager->state = PAGER_EXCLUSIVE;
pPager->origDbSize = pPager->dbSize;
}else{
- rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK);
+ rc = sqlite3Io.xLock(&pPager->fd, RESERVED_LOCK);
if( rc==SQLITE_OK ){
pPager->state = PAGER_RESERVED;
if( exFlag ){
@@ -2867,7 +2867,7 @@ int sqlite3pager_write(void *pData){
store32bits(cksum, pPg, pPager->pageSize);
szPg = pPager->pageSize+8;
store32bits(pPg->pgno, pPg, -4);
- rc = sqlite3OsWrite(&pPager->jfd, &((char*)pData)[-4], szPg);
+ rc = sqlite3Io.xWrite(&pPager->jfd, &((char*)pData)[-4], szPg);
pPager->journalOff += szPg;
TRACE4("JOURNAL %d page %d needSync=%d\n",
PAGERID(pPager), pPg->pgno, pPg->needSync);
@@ -2916,7 +2916,8 @@ int sqlite3pager_write(void *pData){
}else{
store32bits(pPg->pgno, pPg, -4);
CODEC(pPager, pData, pPg->pgno, 7);
- rc = sqlite3OsWrite(&pPager->stfd,((char*)pData)-4, pPager->pageSize+4);
+ rc = sqlite3Io.xWrite(&pPager->stfd,((char*)pData)-4,
+ pPager->pageSize+4);
TRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
CODEC(pPager, pData, pPg->pgno, 0);
if( rc!=SQLITE_OK ){
@@ -3119,7 +3120,7 @@ int sqlite3pager_commit(Pager *pPager){
return SQLITE_OK;
}
if( pPager->dirtyCache==0 ){
- /* Exit early (without doing the time-consuming sqlite3OsSync() calls)
+ /* Exit early (without doing the time-consuming sqlite3Io.xSync() calls)
** if there have been no changes to the database file. */
assert( pPager->needSync==0 );
rc = pager_unwritelock(pPager);
@@ -3278,11 +3279,11 @@ int sqlite3pager_stmt_begin(Pager *pPager){
assert( pPager->journalOpen );
pPager->aInStmt = sqliteMalloc( pPager->dbSize/8 + 1 );
if( pPager->aInStmt==0 ){
- sqlite3OsLock(&pPager->fd, SHARED_LOCK);
+ sqlite3Io.xLock(&pPager->fd, SHARED_LOCK);
return SQLITE_NOMEM;
}
#ifndef NDEBUG
- rc = sqlite3OsFileSize(&pPager->jfd, &pPager->stmtJSize);
+ rc = sqlite3Io.xFileSize(&pPager->jfd, &pPager->stmtJSize);
if( rc ) goto stmt_begin_failed;
assert( pPager->stmtJSize == pPager->journalOff );
#endif
@@ -3315,8 +3316,8 @@ int sqlite3pager_stmt_commit(Pager *pPager){
PgHdr *pPg, *pNext;
TRACE2("STMT-COMMIT %d\n", PAGERID(pPager));
if( !MEMDB ){
- sqlite3OsSeek(&pPager->stfd, 0);
- /* sqlite3OsTruncate(&pPager->stfd, 0); */
+ sqlite3Io.xSeek(&pPager->stfd, 0);
+ /* sqlite3Io.xTruncate(&pPager->stfd, 0); */
sqliteFree( pPager->aInStmt );
pPager->aInStmt = 0;
}
@@ -3519,7 +3520,7 @@ int sqlite3pager_sync(Pager *pPager, const char *zMaster, Pgno nTrunc){
/* Sync the database file. */
if( !pPager->noSync ){
- rc = sqlite3OsSync(&pPager->fd, 0);
+ rc = sqlite3Io.xSync(&pPager->fd, 0);
}
pPager->state = PAGER_SYNCED;
diff --git a/src/pragma.c b/src/pragma.c
index 93707f530..318e80715 100644
--- a/src/pragma.c
+++ b/src/pragma.c
@@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
-** $Id: pragma.c,v 1.103 2005/11/03 02:15:03 drh Exp $
+** $Id: pragma.c,v 1.104 2005/11/26 00:25:03 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -392,7 +392,7 @@ void sqlite3Pragma(
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
}
}else{
- if( zRight[0] && !sqlite3OsIsDirWritable(zRight) ){
+ if( zRight[0] && !sqlite3Io.xIsDirWritable(zRight) ){
sqlite3ErrorMsg(pParse, "not a writable directory");
goto pragma_out;
}
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index 9baf582c4..f928faab7 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -11,7 +11,7 @@
*************************************************************************
** A TCL Interface to SQLite
**
-** $Id: tclsqlite.c,v 1.133 2005/10/05 10:40:15 drh Exp $
+** $Id: tclsqlite.c,v 1.134 2005/11/26 00:25:03 drh Exp $
*/
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
@@ -2059,6 +2059,7 @@ int TCLSH_MAIN(int argc, char **argv){
extern int Sqlitetest3_Init(Tcl_Interp*);
extern int Sqlitetest4_Init(Tcl_Interp*);
extern int Sqlitetest5_Init(Tcl_Interp*);
+ extern int Sqlitetest6_Init(Tcl_Interp*);
extern int Md5_Init(Tcl_Interp*);
extern int Sqlitetestsse_Init(Tcl_Interp*);
@@ -2067,6 +2068,7 @@ int TCLSH_MAIN(int argc, char **argv){
Sqlitetest3_Init(interp);
Sqlitetest4_Init(interp);
Sqlitetest5_Init(interp);
+ Sqlitetest6_Init(interp);
Md5_Init(interp);
#ifdef SQLITE_SSE
Sqlitetestsse_Init(interp);
diff --git a/src/test1.c b/src/test1.c
index 0c0d4a4c9..402ff8c42 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
-** $Id: test1.c,v 1.165 2005/11/25 10:38:22 danielk1977 Exp $
+** $Id: test1.c,v 1.166 2005/11/26 00:25:03 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@@ -1412,29 +1412,6 @@ static int test_errstr(
return TCL_OK;
}
-static int sqlite3_crashparams(
- void * clientData,
- Tcl_Interp *interp,
- int objc,
- Tcl_Obj *CONST objv[]
-){
-#ifdef OS_TEST
- int delay;
- if( objc!=3 ) goto bad_args;
- if( Tcl_GetIntFromObj(interp, objv[1], &delay) ) return TCL_ERROR;
- sqlite3SetCrashParams(delay, Tcl_GetString(objv[2]));
-#endif
- return TCL_OK;
-
-#ifdef OS_TEST
-bad_args:
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- Tcl_GetStringFromObj(objv[0], 0), "<delay> <filename>", 0);
- return TCL_ERROR;
-#endif
-}
-
-
/*
** Usage: breakpoint
**
@@ -2464,7 +2441,7 @@ static int test_sqlite3OsOpenReadWrite(
}
pFile = sqliteMalloc(sizeof(OsFile));
- rc = sqlite3OsOpenReadWrite(Tcl_GetString(objv[1]), pFile, &dummy);
+ rc = sqlite3Io.xOpenReadWrite(Tcl_GetString(objv[1]), pFile, &dummy);
if( rc!=SQLITE_OK ){
sqliteFree(pFile);
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
@@ -2496,7 +2473,7 @@ static int test_sqlite3OsClose(
if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
return TCL_ERROR;
}
- rc = sqlite3OsClose(pFile);
+ rc = sqlite3Io.xClose(pFile);
if( rc!=SQLITE_OK ){
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
return TCL_ERROR;
@@ -2529,16 +2506,16 @@ static int test_sqlite3OsLock(
}
if( 0==strcmp("SHARED", Tcl_GetString(objv[2])) ){
- rc = sqlite3OsLock(pFile, SHARED_LOCK);
+ rc = sqlite3Io.xLock(pFile, SHARED_LOCK);
}
else if( 0==strcmp("RESERVED", Tcl_GetString(objv[2])) ){
- rc = sqlite3OsLock(pFile, RESERVED_LOCK);
+ rc = sqlite3Io.xLock(pFile, RESERVED_LOCK);
}
else if( 0==strcmp("PENDING", Tcl_GetString(objv[2])) ){
- rc = sqlite3OsLock(pFile, PENDING_LOCK);
+ rc = sqlite3Io.xLock(pFile, PENDING_LOCK);
}
else if( 0==strcmp("EXCLUSIVE", Tcl_GetString(objv[2])) ){
- rc = sqlite3OsLock(pFile, EXCLUSIVE_LOCK);
+ rc = sqlite3Io.xLock(pFile, EXCLUSIVE_LOCK);
}else{
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetString(objv[0]),
@@ -2574,7 +2551,7 @@ static int test_sqlite3OsUnlock(
if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
return TCL_ERROR;
}
- rc = sqlite3OsUnlock(pFile, NO_LOCK);
+ rc = sqlite3Io.xUnlock(pFile, NO_LOCK);
if( rc!=SQLITE_OK ){
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
return TCL_ERROR;
@@ -2594,7 +2571,7 @@ static int test_sqlite3OsTempFileName(
char zFile[SQLITE_TEMPNAME_SIZE];
int rc;
- rc = sqlite3OsTempFileName(zFile);
+ rc = sqlite3Io.xTempFileName(zFile);
if( rc!=SQLITE_OK ){
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
return TCL_ERROR;
@@ -3186,7 +3163,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "add_test_collate_needed", test_collate_needed, 0 },
{ "add_test_function", test_function, 0 },
#endif
- { "sqlite3_crashparams", sqlite3_crashparams, 0 },
{ "sqlite3_test_errstr", test_errstr, 0 },
{ "tcl_variable_type", tcl_variable_type, 0 },
};
diff --git a/src/test2.c b/src/test2.c
index 1867fc866..bb02af5da 100644
--- a/src/test2.c
+++ b/src/test2.c
@@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
-** $Id: test2.c,v 1.35 2005/11/04 22:03:30 drh Exp $
+** $Id: test2.c,v 1.36 2005/11/26 00:25:04 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -533,20 +533,20 @@ static int fake_big_file(
}
if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
memset(&fd, 0, sizeof(fd));
- rc = sqlite3OsOpenReadWrite(argv[2], &fd, &readOnly);
+ rc = sqlite3Io.xOpenReadWrite(argv[2], &fd, &readOnly);
if( rc ){
Tcl_AppendResult(interp, "open failed: ", errorName(rc), 0);
return TCL_ERROR;
}
offset = n;
offset *= 1024*1024;
- rc = sqlite3OsSeek(&fd, offset);
+ rc = sqlite3Io.xSeek(&fd, offset);
if( rc ){
Tcl_AppendResult(interp, "seek failed: ", errorName(rc), 0);
return TCL_ERROR;
}
- rc = sqlite3OsWrite(&fd, "Hello, World!", 14);
- sqlite3OsClose(&fd);
+ rc = sqlite3Io.xWrite(&fd, "Hello, World!", 14);
+ sqlite3Io.xClose(&fd);
if( rc ){
Tcl_AppendResult(interp, "write failed: ", errorName(rc), 0);
return TCL_ERROR;
diff --git a/src/test6.c b/src/test6.c
new file mode 100644
index 000000000..f0c5a06e0
--- /dev/null
+++ b/src/test6.c
@@ -0,0 +1,478 @@
+/*
+** 2004 May 22
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains code that modified the OS layer in order to simulate
+** the effect on the database file of an OS crash or power failure. This
+** is used to test the ability of SQLite to recover from those situations.
+*/
+#if SQLITE_TEST /* This file is used for the testing only */
+#include "sqliteInt.h"
+#include "os.h"
+#include "tcl.h"
+
+/*
+** A copy of the original sqlite3Io structure
+*/
+static struct sqlite3IoVtbl origIo;
+
+/*
+** The pAux part of OsFile points to this structure.
+*/
+typedef struct OsTestFile OsTestFile;
+struct OsTestFile {
+ u8 **apBlk; /* Array of blocks that have been written to. */
+ int nBlk; /* Size of apBlock. */
+ int nMaxWrite; /* Largest offset written to. */
+ char *zName; /* File name */
+ OsFile *pBase; /* Base class */
+ OsTestFile *pNext; /* Next in a list of them all */
+};
+
+/*
+** Size of a simulated disk block
+*/
+#define BLOCKSIZE 512
+#define BLOCK_OFFSET(x) ((x) * BLOCKSIZE)
+
+
+/*
+** The following variables control when a simulated crash occurs.
+**
+** If iCrashDelay is non-zero, then zCrashFile contains (full path) name of
+** a file that SQLite will call sqlite3OsSync() on. Each time this happens
+** iCrashDelay is decremented. If iCrashDelay is zero after being
+** decremented, a "crash" occurs during the sync() operation.
+**
+** In other words, a crash occurs the iCrashDelay'th time zCrashFile is
+** synced.
+*/
+static int iCrashDelay = 0;
+static char zCrashFile[500];
+
+/*
+** Set the value of the two crash parameters.
+*/
+static void setCrashParams(int iDelay, char const *zFile){
+ sqlite3OsEnterMutex();
+ assert( strlen(zFile)<sizeof(zCrashFile) );
+ strcpy(zCrashFile, zFile);
+ iCrashDelay = iDelay;
+ sqlite3OsLeaveMutex();
+}
+
+/*
+** File zPath is being sync()ed. Return non-zero if this should
+** cause a crash.
+*/
+static int crashRequired(char const *zPath){
+ int r;
+ int n;
+ sqlite3OsEnterMutex();
+ n = strlen(zCrashFile);
+ if( zCrashFile[n-1]=='*' ){
+ n--;
+ }else if( strlen(zPath)>n ){
+ n = strlen(zPath);
+ }
+ r = 0;
+ if( iCrashDelay>0 && strncmp(zPath, zCrashFile, n)==0 ){
+ iCrashDelay--;
+ if( iCrashDelay<=0 ){
+ r = 1;
+ }
+ }
+ sqlite3OsLeaveMutex();
+ return r;
+}
+
+/*
+** A list of all open files.
+*/
+static OsTestFile *pAllFiles = 0;
+
+/*
+** Initialise the os_test.c specific fields of pFile.
+*/
+static void initFile(OsFile *id, char const *zName){
+ OsTestFile *pFile = sqliteMalloc(sizeof(OsTestFile) + strlen(zName)+1);
+ id->pAux = pFile;
+ pFile->nMaxWrite = 0;
+ pFile->nBlk = 0;
+ pFile->apBlk = 0;
+ pFile->zName = (char *)(&pFile[1]);
+ strcpy(pFile->zName, zName);
+ pFile->pBase = id;
+ pFile->pNext = pAllFiles;
+ pAllFiles = pFile;
+}
+
+/*
+** Undo the work done by initFile. Delete the OsTestFile structure
+** and unlink the structure from the pAllFiles list.
+*/
+static void closeFile(OsFile *id){
+ OsTestFile *pFile = (OsTestFile*)id->pAux;
+ if( pFile==pAllFiles ){
+ pAllFiles = pFile->pNext;
+ }else{
+ OsTestFile *p;
+ for(p=pAllFiles; p->pNext!=pFile; p=p->pNext ){
+ assert( p );
+ }
+ p->pNext = pFile->pNext;
+ }
+ sqliteFree(pFile);
+}
+
+/*
+** Return the current seek offset from the start of the file. This
+** is unix-only code.
+*/
+static i64 osTell(OsTestFile *pFile){
+ return lseek(pFile->pBase->h, 0, SEEK_CUR);
+}
+
+/*
+** Load block 'blk' into the cache of pFile.
+*/
+static int cacheBlock(OsTestFile *pFile, int blk){
+ if( blk>=pFile->nBlk ){
+ int n = ((pFile->nBlk * 2) + 100 + blk);
+ /* if( pFile->nBlk==0 ){ printf("DIRTY %s\n", pFile->zName); } */
+ pFile->apBlk = (u8 **)sqliteRealloc(pFile->apBlk, n * sizeof(u8*));
+ if( !pFile->apBlk ) return SQLITE_NOMEM;
+ memset(&pFile->apBlk[pFile->nBlk], 0, (n - pFile->nBlk)*sizeof(u8*));
+ pFile->nBlk = n;
+ }
+
+ if( !pFile->apBlk[blk] ){
+ i64 filesize;
+ int rc;
+
+ u8 *p = sqliteMalloc(BLOCKSIZE);
+ if( !p ) return SQLITE_NOMEM;
+ pFile->apBlk[blk] = p;
+
+ rc = origIo.xFileSize(pFile->pBase, &filesize);
+ if( rc!=SQLITE_OK ) return rc;
+
+ if( BLOCK_OFFSET(blk)<filesize ){
+ int len = BLOCKSIZE;
+ rc = origIo.xSeek(pFile->pBase, blk*BLOCKSIZE);
+ if( BLOCK_OFFSET(blk+1)>filesize ){
+ len = filesize - BLOCK_OFFSET(blk);
+ }
+ if( rc!=SQLITE_OK ) return rc;
+ rc = origIo.xRead(pFile->pBase, p, len);
+ if( rc!=SQLITE_OK ) return rc;
+ }
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Write the cache of pFile to disk. If crash is non-zero, randomly
+** skip blocks when writing. The cache is deleted before returning.
+*/
+static int writeCache2(OsTestFile *pFile, int crash){
+ int i;
+ int nMax = pFile->nMaxWrite;
+ i64 offset;
+ int rc = SQLITE_OK;
+
+ offset = osTell(pFile);
+ for(i=0; i<pFile->nBlk; i++){
+ u8 *p = pFile->apBlk[i];
+ if( p ){
+ int skip = 0;
+ int trash = 0;
+ if( crash ){
+ char random;
+ sqlite3Randomness(1, &random);
+ if( random & 0x01 ){
+ if( random & 0x02 ){
+ trash = 1;
+#ifdef TRACE_WRITECACHE
+printf("Trashing block %d of %s\n", i, pFile->zName);
+#endif
+ }else{
+ skip = 1;
+#ifdef TRACE_WRITECACHE
+printf("Skiping block %d of %s\n", i, pFile->zName);
+#endif
+ }
+ }else{
+#ifdef TRACE_WRITECACHE
+printf("Writing block %d of %s\n", i, pFile->zName);
+#endif
+ }
+ }
+ if( rc==SQLITE_OK ){
+ rc = origIo.xSeek(pFile->pBase, BLOCK_OFFSET(i));
+ }
+ if( rc==SQLITE_OK && !skip ){
+ int len = BLOCKSIZE;
+ if( BLOCK_OFFSET(i+1)>nMax ){
+ len = nMax-BLOCK_OFFSET(i);
+ }
+ if( len>0 ){
+ if( trash ){
+ sqlite3Randomness(len, p);
+ }
+ rc = origIo.xWrite(pFile->pBase, p, len);
+ }
+ }
+ sqliteFree(p);
+ }
+ }
+ sqliteFree(pFile->apBlk);
+ pFile->nBlk = 0;
+ pFile->apBlk = 0;
+ pFile->nMaxWrite = 0;
+
+ if( rc==SQLITE_OK ){
+ rc = origIo.xSeek(pFile->pBase, offset);
+ }
+ return rc;
+}
+
+/*
+** Write the cache to disk.
+*/
+static int writeCache(OsTestFile *pFile){
+ if( pFile->apBlk ){
+ int c = crashRequired(pFile->zName);
+ if( c ){
+ OsTestFile *p;
+#ifdef TRACE_WRITECACHE
+ printf("\nCrash during sync of %s\n", pFile->zName);
+#endif
+ for(p=pAllFiles; p; p=p->pNext){
+ writeCache2(p, 1);
+ }
+ exit(-1);
+ }else{
+ return writeCache2(pFile, 0);
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Close the file.
+*/
+static int crashClose(OsFile *id){
+ if( id->pAux ) return SQLITE_OK;
+ if( id->isOpen ){
+ /* printf("CLOSE %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */
+ writeCache((OsTestFile*)id->pAux);
+ origIo.xClose(id);
+ }
+ closeFile(id);
+ return SQLITE_OK;
+}
+
+static int crashRead(OsFile *id, void *pBuf, int amt){
+ i64 offset; /* The current offset from the start of the file */
+ i64 end; /* The byte just past the last byte read */
+ int blk; /* Block number the read starts on */
+ int i;
+ u8 *zCsr;
+ int rc = SQLITE_OK;
+ OsTestFile *pFile = (OsTestFile*)id->pAux;
+
+ offset = osTell(pFile);
+ end = offset+amt;
+ blk = (offset/BLOCKSIZE);
+
+ zCsr = (u8 *)pBuf;
+ for(i=blk; i*BLOCKSIZE<end; i++){
+ int off = 0;
+ int len = 0;
+
+
+ if( BLOCK_OFFSET(i) < offset ){
+ off = offset-BLOCK_OFFSET(i);
+ }
+ len = BLOCKSIZE - off;
+ if( BLOCK_OFFSET(i+1) > end ){
+ len = len - (BLOCK_OFFSET(i+1)-end);
+ }
+
+ if( i<pFile->nBlk && pFile->apBlk[i]){
+ u8 *pBlk = pFile->apBlk[i];
+ memcpy(zCsr, &pBlk[off], len);
+ }else{
+ rc = origIo.xSeek(id, BLOCK_OFFSET(i) + off);
+ if( rc!=SQLITE_OK ) return rc;
+ rc = origIo.xRead(id, zCsr, len);
+ if( rc!=SQLITE_OK ) return rc;
+ }
+
+ zCsr += len;
+ }
+ assert( zCsr==&((u8 *)pBuf)[amt] );
+
+ rc = origIo.xSeek(id, end);
+ return rc;
+}
+
+static int crashWrite(OsFile *id, const void *pBuf, int amt){
+ i64 offset; /* The current offset from the start of the file */
+ i64 end; /* The byte just past the last byte written */
+ int blk; /* Block number the write starts on */
+ int i;
+ const u8 *zCsr;
+ int rc = SQLITE_OK;
+ OsTestFile *pFile = (OsTestFile*)id->pAux;
+
+ offset = osTell(pFile);
+ end = offset+amt;
+ blk = (offset/BLOCKSIZE);
+
+ zCsr = (u8 *)pBuf;
+ for(i=blk; i*BLOCKSIZE<end; i++){
+ u8 *pBlk;
+ int off = 0;
+ int len = 0;
+
+ /* Make sure the block is in the cache */
+ rc = cacheBlock(pFile, i);
+ if( rc!=SQLITE_OK ) return rc;
+
+ /* Write into the cache */
+ pBlk = pFile->apBlk[i];
+ assert( pBlk );
+
+ if( BLOCK_OFFSET(i) < offset ){
+ off = offset-BLOCK_OFFSET(i);
+ }
+ len = BLOCKSIZE - off;
+ if( BLOCK_OFFSET(i+1) > end ){
+ len = len - (BLOCK_OFFSET(i+1)-end);
+ }
+ memcpy(&pBlk[off], zCsr, len);
+ zCsr += len;
+ }
+ if( pFile->nMaxWrite<end ){
+ pFile->nMaxWrite = end;
+ }
+ assert( zCsr==&((u8 *)pBuf)[amt] );
+
+ rc = origIo.xSeek(id, end);
+ return rc;
+}
+
+/*
+** Sync the file. First flush the write-cache to disk, then call the
+** real sync() function.
+*/
+static int crashSync(OsFile *id, int dataOnly){
+ int rc;
+ /* printf("SYNC %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */
+ rc = writeCache((OsTestFile*)id->pAux);
+ if( rc!=SQLITE_OK ) return rc;
+ rc = origIo.xSync(id, dataOnly);
+ return rc;
+}
+
+/*
+** Truncate the file. Set the internal OsFile.nMaxWrite variable to the new
+** file size to ensure that nothing in the write-cache past this point
+** is written to disk.
+*/
+static int crashTruncate(OsFile *id, i64 nByte){
+ OsTestFile *pFile = (OsTestFile*)id->pAux;
+ pFile->nMaxWrite = nByte;
+ return origIo.xTruncate(id, nByte);
+}
+
+/*
+** Return the size of the file. If the cache contains a write that extended
+** the file, then return this size instead of the on-disk size.
+*/
+static int crashFileSize(OsFile *id, i64 *pSize){
+ int rc = origIo.xFileSize(id, pSize);
+ OsTestFile *pFile = (OsTestFile*)id->pAux;
+ if( rc==SQLITE_OK && pSize && *pSize<pFile->nMaxWrite ){
+ *pSize = pFile->nMaxWrite;
+ }
+ return rc;
+}
+
+/*
+** The three functions used to open files. All that is required is to
+** initialise the os_test.c specific fields and then call the corresponding
+** os_unix.c function to really open the file.
+*/
+static int crashOpenReadWrite(const char *zFilename, OsFile *id, int *pRdonly){
+ initFile(id, zFilename);
+ return origIo.xOpenReadWrite(zFilename, id, pRdonly);
+}
+static int crashOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
+ initFile(id, zFilename);
+ return origIo.xOpenExclusive(zFilename, id, delFlag);
+}
+static int crashOpenReadOnly(const char *zFilename, OsFile *id){
+ initFile(id, zFilename);
+ return origIo.xOpenReadOnly(zFilename, id);
+}
+
+/*
+** tclcmd: sqlite_crashparams DELAY CRASHFILE
+**
+** This procedure implements a TCL command that enables crash testing
+** in testfixture. Once enabled, crash testing cannot be disabled.
+*/
+static int crashParamsObjCmd(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ int delay;
+ const char *zFile;
+ int nFile;
+ if( objc!=3 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DELAY CRASHFILE");
+ return TCL_ERROR;
+ }
+ if( Tcl_GetIntFromObj(interp, objv[1], &delay) ) return TCL_ERROR;
+ zFile = Tcl_GetStringFromObj(objv[2], &nFile);
+ if( nFile>=sizeof(zCrashFile)-1 ){
+ Tcl_AppendResult(interp, "crash file name too big", 0);
+ return TCL_ERROR;
+ }
+ setCrashParams(delay, zFile);
+ origIo = sqlite3Io;
+ sqlite3Io.xRead = crashRead;
+ sqlite3Io.xWrite = crashWrite;
+ sqlite3Io.xClose = crashClose;
+ sqlite3Io.xSync = crashSync;
+ sqlite3Io.xTruncate = crashTruncate;
+ sqlite3Io.xFileSize = crashFileSize;
+ sqlite3Io.xOpenReadWrite = crashOpenReadWrite;
+ sqlite3Io.xOpenExclusive = crashOpenExclusive;
+ sqlite3Io.xOpenReadOnly = crashOpenReadOnly;
+ return TCL_OK;
+}
+
+/*
+** This procedure registers the TCL procedures defined in this file.
+*/
+int Sqlitetest6_Init(Tcl_Interp *interp){
+ Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0);
+ return TCL_OK;
+}
+
+#endif /* SQLITE_TEST */
diff --git a/src/vacuum.c b/src/vacuum.c
index a8af62908..bf9fd66b9 100644
--- a/src/vacuum.c
+++ b/src/vacuum.c
@@ -14,7 +14,7 @@
** Most of the code in this file may be omitted by defining the
** SQLITE_OMIT_VACUUM macro.
**
-** $Id: vacuum.c,v 1.47 2005/11/04 22:03:30 drh Exp $
+** $Id: vacuum.c,v 1.48 2005/11/26 00:25:04 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -146,7 +146,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
do {
zTemp[nFilename] = '-';
randomName((unsigned char*)&zTemp[nFilename+1]);
- } while( sqlite3OsFileExists(zTemp) );
+ } while( sqlite3Io.xFileExists(zTemp) );
/* Attach the temporary database as 'vacuum_db'. The synchronous pragma
** can be set to 'off' for this file, as it is not recovered if a crash
@@ -300,7 +300,7 @@ end_of_vacuum:
rc = rc2;
}
if( zTemp ){
- sqlite3OsDelete(zTemp);
+ sqlite3Io.xDelete(zTemp);
sqliteFree(zTemp);
}
sqliteFree( zSql );
diff --git a/src/vdbe.c b/src/vdbe.c
index 143a86936..8684af553 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
-** $Id: vdbe.c,v 1.499 2005/11/24 14:34:36 drh Exp $
+** $Id: vdbe.c,v 1.500 2005/11/26 00:25:04 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -422,7 +422,7 @@ int sqlite3VdbeExec(
}
sqlite3VdbePrintOp(p->trace, pc, pOp);
}
- if( p->trace==0 && pc==0 && sqlite3OsFileExists("vdbe_sqltrace") ){
+ if( p->trace==0 && pc==0 && sqlite3Io.xFileExists("vdbe_sqltrace") ){
sqlite3VdbePrintSql(p);
}
#endif
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 9aa22731f..145664044 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -273,7 +273,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){
/* If we never rollback a statement transaction, then statement
** transactions are not needed. So change every OP_Statement
- ** opcode into an OP_Noop. This avoid a call to sqlite3OsOpenExclusive()
+ ** opcode into an OP_Noop. This avoid a call to sqlite3Io.xOpenExclusive()
** which can be expensive on some platforms.
*/
if( hasStatementBegin && !doesStatementRollback ){
@@ -755,7 +755,7 @@ void sqlite3VdbeMakeReady(
#ifdef SQLITE_DEBUG
if( (p->db->flags & SQLITE_VdbeListing)!=0
- || sqlite3OsFileExists("vdbe_explain")
+ || sqlite3Io.xFileExists("vdbe_explain")
){
int i;
printf("VDBE Program Listing:\n");
@@ -764,7 +764,7 @@ void sqlite3VdbeMakeReady(
sqlite3VdbePrintOp(stdout, i, &p->aOp[i]);
}
}
- if( sqlite3OsFileExists("vdbe_trace") ){
+ if( sqlite3Io.xFileExists("vdbe_trace") ){
p->trace = stdout;
}
#endif
@@ -978,11 +978,11 @@ static int vdbeCommit(sqlite3 *db){
if( !zMaster ){
return SQLITE_NOMEM;
}
- }while( sqlite3OsFileExists(zMaster) );
+ }while( sqlite3Io.xFileExists(zMaster) );
/* Open the master journal. */
memset(&master, 0, sizeof(master));
- rc = sqlite3OsOpenExclusive(zMaster, &master, 0);
+ rc = sqlite3Io.xOpenExclusive(zMaster, &master, 0);
if( rc!=SQLITE_OK ){
sqliteFree(zMaster);
return rc;
@@ -1003,10 +1003,10 @@ static int vdbeCommit(sqlite3 *db){
if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){
needSync = 1;
}
- rc = sqlite3OsWrite(&master, zFile, strlen(zFile)+1);
+ rc = sqlite3Io.xWrite(&master, zFile, strlen(zFile)+1);
if( rc!=SQLITE_OK ){
- sqlite3OsClose(&master);
- sqlite3OsDelete(zMaster);
+ sqlite3Io.xClose(&master);
+ sqlite3Io.xDelete(zMaster);
sqliteFree(zMaster);
return rc;
}
@@ -1018,11 +1018,11 @@ static int vdbeCommit(sqlite3 *db){
** the master journal file is store in so that it gets synced too.
*/
zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);
- rc = sqlite3OsOpenDirectory(zMainFile, &master);
+ rc = sqlite3Io.xOpenDirectory(zMainFile, &master);
if( rc!=SQLITE_OK ||
- (needSync && (rc=sqlite3OsSync(&master,0))!=SQLITE_OK) ){
- sqlite3OsClose(&master);
- sqlite3OsDelete(zMaster);
+ (needSync && (rc=sqlite3Io.xSync(&master,0))!=SQLITE_OK) ){
+ sqlite3Io.xClose(&master);
+ sqlite3Io.xDelete(zMaster);
sqliteFree(zMaster);
return rc;
}
@@ -1042,23 +1042,23 @@ static int vdbeCommit(sqlite3 *db){
if( pBt && sqlite3BtreeIsInTrans(pBt) ){
rc = sqlite3BtreeSync(pBt, zMaster);
if( rc!=SQLITE_OK ){
- sqlite3OsClose(&master);
+ sqlite3Io.xClose(&master);
sqliteFree(zMaster);
return rc;
}
}
}
- sqlite3OsClose(&master);
+ sqlite3Io.xClose(&master);
/* Delete the master journal file. This commits the transaction. After
** doing this the directory is synced again before any individual
** transaction files are deleted.
*/
- rc = sqlite3OsDelete(zMaster);
+ rc = sqlite3Io.xDelete(zMaster);
assert( rc==SQLITE_OK );
sqliteFree(zMaster);
zMaster = 0;
- rc = sqlite3OsSyncDirectory(zMainFile);
+ rc = sqlite3Io.xSyncDirectory(zMainFile);
if( rc!=SQLITE_OK ){
/* This is not good. The master journal file has been deleted, but
** the directory sync failed. There is no completely safe course of