]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Modify the crash-recovery test code in test6.c for 3.5. Also change some other code...
authordanielk1977 <danielk1977@noemail.net>
Wed, 15 Aug 2007 17:08:46 +0000 (17:08 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Wed, 15 Aug 2007 17:08:46 +0000 (17:08 +0000)
FossilOrigin-Name: af9503daf3f7703fcddad754bc1dc9e179830b6e

manifest
manifest.uuid
src/os.c
src/os.h
src/os_unix.c
src/pager.c
src/sqlite.h.in
src/test2.c
src/test6.c
src/vdbeaux.c

index 65cbbe048d285862db79398030c1e082b37b44e0..bf7b4faa69d2598435eb48f03c76d123dc3c568a 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sa\sdebugging\smemory\sallocator.\s(CVS\s4227)
-D 2007-08-15T17:07:57
+C Modify\sthe\scrash-recovery\stest\scode\sin\stest6.c\sfor\s3.5.\sAlso\schange\ssome\sother\scode\sto\suse\sthe\snew\ssqlite3_io_methods\sinterface.\sLots\sof\sthings\sare\sbroken\snow.\s(CVS\s4228)
+D 2007-08-15T17:08:46
 F Makefile.in 0c0e53720f658c7a551046442dd7afba0b72bfbe
 F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -91,18 +91,18 @@ F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217
 F src/mem1.c ef73642a171d174cd556d0168f8edbceaf94933b
 F src/mem2.c b8173ddcca23e99829617185154a35a6f046b214
 F src/mutex.c 667dae0de95f8fb92a3ffc8c3f20c0d26115a1a6
-F src/os.c 1f10b47acc1177fb9225edb4f5f0d25ed716f9cb
-F src/os.h cea2e179bb33f4fc09dbb9fcd51b2246544bd2db
+F src/os.c e2faefbe0f5a8ca5e3b1c49ee1b5c6cfa0f0e279
+F src/os.h 8eff07babf74e5bc3f895f8a6c7c294dad5ff997
 F src/os_common.h a5c446d3b93f09f369d13bf217de4bed3437dd1c
 F src/os_os2.c cba4e96fadb949076c717108fe0599d1a3c2e446
 F src/os_os2.h e5f17dd69333632bbc3112881ea407c37d245eb3
 F src/os_test.c 49833426101f99aee4bb5f6a44b7c4b2029fda1c
 F src/os_test.h 903c93554c23d88f34f667f1979e4a1cee792af3
-F src/os_unix.c 9d2a421acc607262e63ccf31e3fe86e5f2520af6
+F src/os_unix.c 05ad65c32b4937fd47b17b472955aa5dfc438074
 F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e
 F src/os_win.c d868d5f9e95ec9c1b9e2a30c54c996053db6dddd
 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
-F src/pager.c cdf561d3ae4009be902df714da4518dc3522e206
+F src/pager.c 05ea9dcbc4de4e9d9ca332ca1f8a9ba65fe2cbf5
 F src/pager.h 94110a5570dca30d54a883e880a3633b2e4c05ae
 F src/parse.y ad2ce25665be7f7303137f774a4e3e72e0d036ff
 F src/pragma.c 7914a6b9ea05f158800116dfcae11e52ab8e39c4
@@ -112,18 +112,18 @@ F src/random.c 6119474a6f6917f708c1dee25b9a8e519a620e88
 F src/select.c 3b167744fc375bddfddcef87feb18f5171737677
 F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
 F src/shell.c ac29402b538515fa4697282387be9c1205e6e9eb
-F src/sqlite.h.in 025e9fd6c519f2945296a9db46ca9da4571c22d7
+F src/sqlite.h.in 165913eb3426fbaa8a2a51d87f84593bfe5bee15
 F src/sqlite3ext.h a27bedc222df5e5f0f458ac99726d0483b953a91
 F src/sqliteInt.h fc9f6e8d916e182c04983a089c4ce4057fac5003
 F src/sqliteLimit.h f14609c27636ebc217c9603ade26dbdd7d0f6afa
 F src/table.c a8de75bcedf84d4060d804264b067ab3b1a3561d
 F src/tclsqlite.c 648e6f53041ce4974234d4963e71680926760925
 F src/test1.c 94bd41c24a4d8d782e39c1275421511587d8b293
-F src/test2.c 24458b17ab2f3c90cbc1c8446bd7ffe69be62f88
+F src/test2.c 5c3edc610852a8f67990cd08c5d5dbb79e3f8db9
 F src/test3.c a280931fb40222b7c90da45eea926459beee8904
 F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25
 F src/test5.c c40a4cf43266c1c6da7bcb737d294304a177e6cc
-F src/test6.c 2c4ed21787944bd8896cba80d4a544d8bed5473e
+F src/test6.c 4d812a5ea1fe08693f4189bfc974b341102a3bea
 F src/test7.c 03fa8d787f6aebc6d1f72504d52f33013ad2c8e3
 F src/test8.c 27a61c60f736066646a9e9ca21acdfdf0f3ea11e
 F src/test9.c c0f38f7795cc51d37db6c63874d90f40f10d0f0e
@@ -147,7 +147,7 @@ F src/vdbe.c cf973bd1af5fbda845b0f759bb06eb19ff42e215
 F src/vdbe.h 001c5b257567c1d3de7feb2203aac71d0d7b16a3
 F src/vdbeInt.h c3514903cad9e36d6b3242be20261351d09db56c
 F src/vdbeapi.c 220b81132abaf0f620edb8da48799a77daef12a7
-F src/vdbeaux.c d626e0f8cd78b4280bcb7af25d5c5566348ba87a
+F src/vdbeaux.c 8e6dbe3dac3bdd7d37c87ba553059b5251ba07e5
 F src/vdbeblob.c bb30b3e387c35ba869949494b2736aff97159470
 F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f
 F src/vdbemem.c ca4d3994507cb0a9504820293af69f5c778b4abd
@@ -528,7 +528,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P c0fa3769790af199a4c8715c80bb8ff900730520
-R afa459b840a3b96de70924b91a0e1dbb
-U drh
-Z 9341f1481e29775e7a036e24546ed5fc
+P 8d2d1c4ff9dca61f75e3048107ee9712d346a28c
+R 7d9819ae0c3408fa1555b7b8d9a48850
+U danielk1977
+Z 41f21c80ce49e631fe5dbf7930bb9145
index ebda03082640b17db60515ce73d9936a79ff9c96..ce612004a486f257c4d5da31d7abed7f70d65e8a 100644 (file)
@@ -1 +1 @@
-8d2d1c4ff9dca61f75e3048107ee9712d346a28c
\ No newline at end of file
+af9503daf3f7703fcddad754bc1dc9e179830b6e
\ No newline at end of file
index 7cd1ab99dde3ff7c1964d54f6b4c810fb7a6865d..d55cfa703287f079b4f60a606267f816d1efbcf3 100644 (file)
--- a/src/os.c
+++ b/src/os.c
 
 /*
 ** The following routines are convenience wrappers around methods
-** of the OsFile object.  This is mostly just syntactic sugar.  All
+** of the sqlite3_file object.  This is mostly just syntactic sugar. All
 ** of this would be completely automatic if SQLite were coded using
 ** C++ instead of plain old C.
 */
-int sqlite3OsClose(OsFile **pId){
-  OsFile *id;
+int sqlite3OsClose(sqlite3_file **pId){
+  int rc = SQLITE_OK;
+  sqlite3_file *id;
   if( pId!=0 && (id = *pId)!=0 ){
-    return id->pMethod->xClose(pId);
-  }else{
-    return SQLITE_OK;
+    rc = id->pMethods->xClose(id);
+    if( rc==SQLITE_OK ){
+      *pId = 0;
+    }
   }
+  return rc;
 }
-int sqlite3OsOpenDirectory(OsFile *id, const char *zName){
-  return id->pMethod->xOpenDirectory(id, zName);
+int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){
+  return id->pMethods->xRead(id, pBuf, amt, offset);
 }
-int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
-  return id->pMethod->xRead(id, pBuf, amt);
+int sqlite3OsWrite(sqlite3_file *id, const void *pBuf, int amt, i64 offset){
+  return id->pMethods->xWrite(id, pBuf, amt, offset);
 }
-int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
-  return id->pMethod->xWrite(id, pBuf, amt);
+int sqlite3OsTruncate(sqlite3_file *id, i64 size){
+  return id->pMethods->xTruncate(id, size);
 }
-int sqlite3OsSeek(OsFile *id, i64 offset){
-  return id->pMethod->xSeek(id, offset);
+int sqlite3OsSync(sqlite3_file *id, int fullsync){
+  return id->pMethods->xSync(id, fullsync);
 }
-int sqlite3OsTruncate(OsFile *id, i64 size){
-  return id->pMethod->xTruncate(id, size);
+int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
+  return id->pMethods->xFileSize(id, pSize);
 }
-int sqlite3OsSync(OsFile *id, int fullsync){
-  return id->pMethod->xSync(id, fullsync);
+int sqlite3OsLock(sqlite3_file *id, int lockType){
+  return id->pMethods->xLock(id, lockType);
 }
-void sqlite3OsSetFullSync(OsFile *id, int value){
-  id->pMethod->xSetFullSync(id, value);
+int sqlite3OsUnlock(sqlite3_file *id, int lockType){
+  return id->pMethods->xUnlock(id, lockType);
 }
-int sqlite3OsFileSize(OsFile *id, i64 *pSize){
-  return id->pMethod->xFileSize(id, pSize);
+int sqlite3OsBreakLock(sqlite3_file *id){
+  return id->pMethods->xBreakLock(id);
 }
-int sqlite3OsLock(OsFile *id, int lockType){
-  return id->pMethod->xLock(id, lockType);
+int sqlite3OsCheckReservedLock(sqlite3_file *id){
+  return id->pMethods->xCheckReservedLock(id);
 }
-int sqlite3OsUnlock(OsFile *id, int lockType){
-  return id->pMethod->xUnlock(id, lockType);
-}
-int sqlite3OsCheckReservedLock(OsFile *id){
-  return id->pMethod->xCheckReservedLock(id);
-}
-int sqlite3OsSectorSize(OsFile *id){
-  int (*xSectorSize)(OsFile*) = id->pMethod->xSectorSize;
+int sqlite3OsSectorSize(sqlite3_file *id){
+  int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize;
   return xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE;
 }
+int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
+  return id->pMethods->xDeviceCharacteristics(id);
+}
 
 #if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
   /* These methods are currently only used for testing and debugging. */
-  int sqlite3OsFileHandle(OsFile *id){
-    return id->pMethod->xFileHandle(id);
+  int sqlite3OsFileHandle(sqlite3_file *id){
+    /* return id->pMethods->xFileHandle(id); */
+    return 0;
   }
-  int sqlite3OsLockState(OsFile *id){
-    return id->pMethod->xLockState(id);
+  int sqlite3OsLockState(sqlite3_file *id){
+    /* return id->pMethods->xLockState(id); */
+    return 0;
   }
 #endif
 
index 76a9f2c48e87e390f4d5dfc4908fa7e80aebf23e..30bc914433b44e20eb3e21aa61d41cf1fad4ca7d 100644 (file)
--- a/src/os.h
+++ b/src/os.h
@@ -348,27 +348,28 @@ extern unsigned int sqlite3_pending_byte;
 /*
 ** Prototypes for operating system interface routines.
 */
-int sqlite3OsClose(OsFile**);
-int sqlite3OsOpenDirectory(OsFile*, const char*);
-int sqlite3OsRead(OsFile*, void*, int amt);
-int sqlite3OsWrite(OsFile*, const void*, int amt);
-int sqlite3OsSeek(OsFile*, i64 offset);
-int sqlite3OsTruncate(OsFile*, i64 size);
-int sqlite3OsSync(OsFile*, int);
-void sqlite3OsSetFullSync(OsFile *id, int setting);
-int sqlite3OsFileSize(OsFile*, i64 *pSize);
-int sqlite3OsLock(OsFile*, int);
-int sqlite3OsUnlock(OsFile*, int);
-int sqlite3OsCheckReservedLock(OsFile *id);
-int sqlite3OsOpenReadWrite(const char*, OsFile**, int*);
-int sqlite3OsOpenExclusive(const char*, OsFile**, int);
-int sqlite3OsOpenReadOnly(const char*, OsFile**);
+int sqlite3OsClose(sqlite3_file**);
+int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
+int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset);
+int sqlite3OsTruncate(sqlite3_file*, i64 size);
+int sqlite3OsSync(sqlite3_file*, int);
+int sqlite3OsFileSize(sqlite3_file*, i64 *pSize);
+int sqlite3OsLock(sqlite3_file*, int);
+int sqlite3OsUnlock(sqlite3_file*, int);
+int sqlite3OsBreakLock(sqlite3_file*);
+int sqlite3OsCheckReservedLock(sqlite3_file *id);
+int sqlite3OsSectorSize(sqlite3_file *id);
+int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
+
+int sqlite3OsOpenReadWrite(const char*, sqlite3_file**, int*);
+int sqlite3OsOpenExclusive(const char*, sqlite3_file**, int);
+int sqlite3OsOpenReadOnly(const char*, sqlite3_file**);
+
 int sqlite3OsDelete(const char*);
 int sqlite3OsFileExists(const char*);
 char *sqlite3OsFullPathname(const char*);
 int sqlite3OsIsDirWritable(char*);
 int sqlite3OsSyncDirectory(const char*);
-int sqlite3OsSectorSize(OsFile *id);
 int sqlite3OsTempFileName(char*);
 int sqlite3OsRandomSeed(char*);
 int sqlite3OsSleep(int ms);
@@ -386,8 +387,8 @@ void *sqlite3OsDlsym(void*, const char*);
 int sqlite3OsDlclose(void*);
 
 #if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
-  int sqlite3OsFileHandle(OsFile *id);
-  int sqlite3OsLockState(OsFile *id);
+  int sqlite3OsFileHandle(sqlite3_file *id);
+  int sqlite3OsLockState(sqlite3_file *id);
 #endif
 
 /*
@@ -409,9 +410,9 @@ int sqlite3OsDlclose(void*);
 ** operating system interfaces or behaviors.
 */
 struct sqlite3OsVtbl {
-  int (*xOpenReadWrite)(const char*, OsFile**, int*);
-  int (*xOpenExclusive)(const char*, OsFile**, int);
-  int (*xOpenReadOnly)(const char*, OsFile**);
+  int (*xOpenReadWrite)(const char*, sqlite3_file**, int*);
+  int (*xOpenExclusive)(const char*, sqlite3_file**, int);
+  int (*xOpenReadOnly)(const char*, sqlite3_file**);
 
   int (*xDelete)(const char*);
   int (*xFileExists)(const char*);
index 91418914ce53e1808883b03ba1dcd19cfd38c291..dc223d929e758bb328c4a5962fb72ad4d98d1392 100644 (file)
@@ -82,7 +82,7 @@
 */
 typedef struct unixFile unixFile;
 struct unixFile {
-  IoMethod const *pMethod;  /* Always the first entry */
+  sqlite3_io_methods const *pMethod;  /* Always the first entry */
   struct openCnt *pOpen;    /* Info about all open fd's on this inode */
   struct lockInfo *pLock;   /* Info about locks on this inode */
 #ifdef SQLITE_ENABLE_LOCKING_STYLE
@@ -99,6 +99,7 @@ struct unixFile {
 #endif
 };
 
+
 /*
 ** Provide the ability to override some OS-layer functions during
 ** testing.  This is used to simulate OS crashes to verify that 
@@ -106,13 +107,15 @@ struct unixFile {
 */
 #ifdef SQLITE_CRASH_TEST
   extern int sqlite3CrashTestEnable;
-  extern int sqlite3CrashOpenReadWrite(const char*, OsFile**, int*);
-  extern int sqlite3CrashOpenExclusive(const char*, OsFile**, int);
-  extern int sqlite3CrashOpenReadOnly(const char*, OsFile**, int);
-# define CRASH_TEST_OVERRIDE(X,A,B,C) \
-    if(sqlite3CrashTestEnable){ return X(A,B,C); }
+  int sqlite3CrashFileWrap(sqlite3_file *, const char *, sqlite3_file **);
+  static int CRASH_TEST_OVERRIDE(const char *zFile, sqlite3_file **pId, int rc){
+    if( rc==SQLITE_OK && sqlite3CrashTestEnable ){
+      rc = sqlite3CrashFileWrap(*pId, zFile, pId); 
+    }
+    return rc;
+  }
 #else
-# define CRASH_TEST_OVERRIDE(X,A,B,C)  /* no-op */
+# define CRASH_TEST_OVERRIDE(A,B,C) C
 #endif
 
 
@@ -801,7 +804,7 @@ int sqlite3UnixFileExists(const char *zFilename){
 /* Forward declaration */
 static int allocateUnixFile(
   int h,                    /* File descriptor of the open file */
-  OsFile **pId,             /* Write the real file descriptor here */
+  sqlite3_file **pId,       /* Write the real file descriptor here */
   const char *zFilename,    /* Name of the file being opened */
   int delFlag               /* If true, make sure the file deletes on close */
 );
@@ -821,12 +824,11 @@ static int allocateUnixFile(
 */
 int sqlite3UnixOpenReadWrite(
   const char *zFilename,
-  OsFile **pId,
+  sqlite3_file **pId,
   int *pReadonly
 ){
   int h;
   
-  CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadWrite, zFilename, pId, pReadonly);
   assert( 0==*pId );
   h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY,
                         SQLITE_DEFAULT_FILE_PERMISSIONS);
@@ -844,7 +846,10 @@ int sqlite3UnixOpenReadWrite(
   }else{
     *pReadonly = 0;
   }
-  return allocateUnixFile(h, pId, zFilename, 0);
+
+  return CRASH_TEST_OVERRIDE(
+    zFilename, pId, allocateUnixFile(h, pId, zFilename, 0)
+  );
 }
 
 
@@ -862,10 +867,13 @@ int sqlite3UnixOpenReadWrite(
 **
 ** On failure, return SQLITE_CANTOPEN.
 */
-int sqlite3UnixOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
+int sqlite3UnixOpenExclusive(
+  const char *zFilename, 
+  sqlite3_file **pId, 
+  int delFlag
+){
   int h;
 
-  CRASH_TEST_OVERRIDE(sqlite3CrashOpenExclusive, zFilename, pId, delFlag);
   assert( 0==*pId );
   h = open(zFilename,
                 O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY,
@@ -873,7 +881,9 @@ int sqlite3UnixOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
   if( h<0 ){
     return SQLITE_CANTOPEN;
   }
-  return allocateUnixFile(h, pId, zFilename, delFlag);
+  return CRASH_TEST_OVERRIDE(
+    zFilename, pId, allocateUnixFile(h, pId, zFilename, delFlag)
+  );
 }
 
 /*
@@ -883,16 +893,17 @@ int sqlite3UnixOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
 **
 ** On failure, return SQLITE_CANTOPEN.
 */
-int sqlite3UnixOpenReadOnly(const char *zFilename, OsFile **pId){
+int sqlite3UnixOpenReadOnly(const char *zFilename, sqlite3_file **pId){
   int h;
   
-  CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadOnly, zFilename, pId, 0);
   assert( 0==*pId );
   h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
   if( h<0 ){
     return SQLITE_CANTOPEN;
   }
-  return allocateUnixFile(h, pId, zFilename, 0);
+  return CRASH_TEST_OVERRIDE(
+    zFilename, pId, allocateUnixFile(h, pId, zFilename, 0)
+  );
 }
 
 /*
@@ -994,29 +1005,26 @@ int sqlite3UnixIsDirWritable(char *zBuf){
 ** Seek to the offset in id->offset then read cnt bytes into pBuf.
 ** Return the number of bytes actually read.  Update the offset.
 */
-static int seekAndRead(unixFile *id, void *pBuf, int cnt){
+static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
   int got;
   i64 newOffset;
   TIMER_START;
 #if defined(USE_PREAD)
-  got = pread(id->h, pBuf, cnt, id->offset);
+  got = pread(id->h, pBuf, cnt, offset);
   SimulateIOError( got = -1 );
 #elif defined(USE_PREAD64)
-  got = pread64(id->h, pBuf, cnt, id->offset);
+  got = pread64(id->h, pBuf, cnt, offset);
   SimulateIOError( got = -1 );
 #else
-  newOffset = lseek(id->h, id->offset, SEEK_SET);
+  newOffset = lseek(id->h, offset, SEEK_SET);
   SimulateIOError( newOffset-- );
-  if( newOffset!=id->offset ){
+  if( newOffset!=offset ){
     return -1;
   }
   got = read(id->h, pBuf, cnt);
 #endif
   TIMER_END;
   OSTRACE5("READ    %-3d %5d %7lld %d\n", id->h, got, id->offset, TIMER_ELAPSED);
-  if( got>0 ){
-    id->offset += got;
-  }
   return got;
 }
 
@@ -1025,10 +1033,15 @@ static int seekAndRead(unixFile *id, void *pBuf, int cnt){
 ** bytes were read successfully and SQLITE_IOERR if anything goes
 ** wrong.
 */
-static int unixRead(OsFile *id, void *pBuf, int amt){
+static int unixRead(
+  sqlite3_file *id, 
+  void *pBuf, 
+  int amt,
+  sqlite3_int64 offset
+){
   int got;
   assert( id );
-  got = seekAndRead((unixFile*)id, pBuf, amt);
+  got = seekAndRead((unixFile*)id, offset, pBuf, amt);
   if( got==amt ){
     return SQLITE_OK;
   }else if( got<0 ){
@@ -1043,26 +1056,23 @@ static int unixRead(OsFile *id, void *pBuf, int amt){
 ** Seek to the offset in id->offset then read cnt bytes into pBuf.
 ** Return the number of bytes actually read.  Update the offset.
 */
-static int seekAndWrite(unixFile *id, const void *pBuf, int cnt){
+static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
   int got;
   i64 newOffset;
   TIMER_START;
 #if defined(USE_PREAD)
-  got = pwrite(id->h, pBuf, cnt, id->offset);
+  got = pwrite(id->h, pBuf, cnt, offset);
 #elif defined(USE_PREAD64)
-  got = pwrite64(id->h, pBuf, cnt, id->offset);
+  got = pwrite64(id->h, pBuf, cnt, offset);
 #else
-  newOffset = lseek(id->h, id->offset, SEEK_SET);
-  if( newOffset!=id->offset ){
+  newOffset = lseek(id->h, offset, SEEK_SET);
+  if( newOffset!=offset ){
     return -1;
   }
   got = write(id->h, pBuf, cnt);
 #endif
   TIMER_END;
-  OSTRACE5("WRITE   %-3d %5d %7lld %d\n", id->h, got, id->offset, TIMER_ELAPSED);
-  if( got>0 ){
-    id->offset += got;
-  }
+  OSTRACE5("WRITE   %-3d %5d %7lld %d\n", id->h, got, offset, TIMER_ELAPSED);
   return got;
 }
 
@@ -1071,12 +1081,18 @@ static int seekAndWrite(unixFile *id, const void *pBuf, int cnt){
 ** Write data from a buffer into a file.  Return SQLITE_OK on success
 ** or some other error code on failure.
 */
-static int unixWrite(OsFile *id, const void *pBuf, int amt){
+static int unixWrite(
+  sqlite3_file *id, 
+  const void *pBuf, 
+  int amt,
+  sqlite3_int64 offset 
+){
   int wrote = 0;
   assert( id );
   assert( amt>0 );
-  while( amt>0 && (wrote = seekAndWrite((unixFile*)id, pBuf, amt))>0 ){
+  while( amt>0 && (wrote = seekAndWrite((unixFile*)id, offset, pBuf, amt))>0 ){
     amt -= wrote;
+    offset += wrote;
     pBuf = &((char*)pBuf)[wrote];
   }
   SimulateIOError(( wrote=(-1), amt=1 ));
@@ -1205,7 +1221,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.
 */
-static int unixSync(OsFile *id, int dataOnly){
+static int unixSync(sqlite3_file *id, int dataOnly){
   int rc;
   unixFile *pFile = (unixFile*)id;
   assert( pFile );
@@ -1272,7 +1288,7 @@ int sqlite3UnixSyncDirectory(const char *zDirname){
 /*
 ** Truncate an open file to a specified size
 */
-static int unixTruncate(OsFile *id, i64 nByte){
+static int unixTruncate(sqlite3_file *id, i64 nByte){
   int rc;
   assert( id );
   rc = ftruncate(((unixFile*)id)->h, (off_t)nByte);
@@ -1287,7 +1303,7 @@ static int unixTruncate(OsFile *id, i64 nByte){
 /*
 ** Determine the current size of a file in bytes
 */
-static int unixFileSize(OsFile *id, i64 *pSize){
+static int unixFileSize(sqlite3_file *id, i64 *pSize){
   int rc;
   struct stat buf;
   assert( id );
@@ -1306,7 +1322,7 @@ static int unixFileSize(OsFile *id, i64 *pSize){
 ** non-zero.  If the file is unlocked or holds only SHARED locks, then
 ** return zero.
 */
-static int unixCheckReservedLock(OsFile *id){
+static int unixCheckReservedLock(sqlite3_file *id){
   int r = 0;
   unixFile *pFile = (unixFile*)id;
 
@@ -1362,7 +1378,7 @@ static int unixCheckReservedLock(OsFile *id){
 ** This routine will only increase a lock.  Use the sqlite3OsUnlock()
 ** routine to lower a locking level.
 */
-static int unixLock(OsFile *id, int locktype){
+static int unixLock(sqlite3_file *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
@@ -1564,7 +1580,7 @@ end_lock:
 ** If the locking level of the file descriptor is already at or below
 ** the requested locking level, this routine is a no-op.
 */
-static int unixUnlock(OsFile *id, int locktype){
+static int unixUnlock(sqlite3_file *id, int locktype){
   struct lockInfo *pLock;
   struct flock lock;
   int rc = SQLITE_OK;
@@ -1650,44 +1666,42 @@ static int unixUnlock(OsFile *id, int locktype){
 /*
 ** Close a file.
 */
-static int unixClose(OsFile **pId){
-  unixFile *id = (unixFile*)*pId;
-
-  if( !id ) return SQLITE_OK;
-  unixUnlock(*pId, NO_LOCK);
-  if( id->dirfd>=0 ) close(id->dirfd);
-  id->dirfd = -1;
+static int unixClose(sqlite3_file *id){
+  unixFile *pFile = (unixFile *)id;
+  if( !pFile ) return SQLITE_OK;
+  unixUnlock(id, NO_LOCK);
+  if( pFile->dirfd>=0 ) close(pFile->dirfd);
+  pFile->dirfd = -1;
   sqlite3OsEnterMutex();
 
-  if( id->pOpen->nLock ){
+  if( pFile->pOpen->nLock ){
     /* If there are outstanding locks, do not actually close the file just
     ** yet because that would clear those locks.  Instead, add the file
     ** descriptor to pOpen->aPending.  It will be automatically closed when
     ** the last lock is cleared.
     */
     int *aNew;
-    struct openCnt *pOpen = id->pOpen;
+    struct openCnt *pOpen = pFile->pOpen;
     aNew = realloc( pOpen->aPending, (pOpen->nPending+1)*sizeof(int) );
     if( aNew==0 ){
       /* If a malloc fails, just leak the file descriptor */
     }else{
       pOpen->aPending = aNew;
-      pOpen->aPending[pOpen->nPending] = id->h;
+      pOpen->aPending[pOpen->nPending] = pFile->h;
       pOpen->nPending++;
     }
   }else{
     /* There are no outstanding locks so we can close the file immediately */
-    close(id->h);
+    close(pFile->h);
   }
-  releaseLockInfo(id->pLock);
-  releaseOpenCnt(id->pOpen);
+  releaseLockInfo(pFile->pLock);
+  releaseOpenCnt(pFile->pOpen);
 
   sqlite3OsLeaveMutex();
-  id->isOpen = 0;
-  OSTRACE2("CLOSE   %-3d\n", id->h);
+  pFile->isOpen = 0;
+  OSTRACE2("CLOSE   %-3d\n", pFile->h);
   OpenCounter(-1);
   sqlite3ThreadSafeFree(id);
-  *pId = 0;
   return SQLITE_OK;
 }
 
@@ -2348,30 +2362,37 @@ static int unixLockState(OsFile *id){
 ** a database and it's journal file) that the sector size will be the
 ** same for both.
 */
-static int unixSectorSize(OsFile *id){
+static int unixSectorSize(sqlite3_file *id){
   return SQLITE_DEFAULT_SECTOR_SIZE;
 }
 
+static int unixDeviceCharacteristics(sqlite3_file *id){
+  return 0;
+}
+
+static int unixBreakLock(sqlite3_file *id){
+  assert(!"TODO: unixBreakLock()");
+  return 0;
+}
+
 /*
 ** This vector defines all the methods that can operate on an OsFile
 ** for unix.
 */
-static const IoMethod sqlite3UnixIoMethod = {
+static const sqlite3_io_methods sqlite3UnixIoMethod = {
+  1,                        /* iVersion */
   unixClose,
-  unixOpenDirectory,
   unixRead,
   unixWrite,
-  unixSeek,
   unixTruncate,
   unixSync,
-  unixSetFullSync,
-  unixFileHandle,
   unixFileSize,
   unixLock,
   unixUnlock,
-  unixLockState,
   unixCheckReservedLock,
+  unixBreakLock,
   unixSectorSize,
+  unixDeviceCharacteristics
 };
 
 #ifdef SQLITE_ENABLE_LOCKING_STYLE
@@ -2573,7 +2594,7 @@ static int allocateUnixFile(
 #else /* SQLITE_ENABLE_LOCKING_STYLE */
 static int allocateUnixFile(
   int h,                 /* Open file descriptor on file being opened */
-  OsFile **pId,          /* Write the resul unixFile structure here */
+  sqlite3_file **pId,    /* Write the resul unixFile structure here */
   const char *zFilename, /* Name of the file being opened */
   int delFlag            /* If true, delete the file on or before closing */
 ){
@@ -2611,7 +2632,7 @@ static int allocateUnixFile(
   }else{
     *pNew = f;
     pNew->pMethod = &sqlite3UnixIoMethod;
-    *pId = (OsFile*)pNew;
+    *pId = (sqlite3_file*)pNew;
     OpenCounter(+1);
     return SQLITE_OK;
   }
index 1202b779542dbd461dfab7b828bfee4627b25f46..35a2667da63478ae3ce2431ab612db02eeef07e9 100644 (file)
@@ -18,7 +18,7 @@
 ** file simultaneously, or one process from reading the database while
 ** another is writing.
 **
-** @(#) $Id: pager.c,v 1.355 2007/08/11 00:26:21 drh Exp $
+** @(#) $Id: pager.c,v 1.356 2007/08/15 17:08:46 danielk1977 Exp $
 */
 #ifndef SQLITE_OMIT_DISKIO
 #include "sqliteInt.h"
@@ -50,7 +50,7 @@
 ** to print out file-descriptors. 
 **
 ** PAGERID() takes a pointer to a Pager struct as it's argument. The
-** associated file-descriptor is returned. FILEHANDLEID() takes an OsFile
+** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file
 ** struct as it's argument.
 */
 #define PAGERID(p) ((int)(p->fd))
@@ -336,8 +336,8 @@ struct Pager {
   char *zFilename;            /* Name of the database file */
   char *zJournal;             /* Name of the journal file */
   char *zDirectory;           /* Directory hold database and journal files */
-  OsFile *fd, *jfd;           /* File descriptors for database and journal */
-  OsFile *stfd;               /* File descriptor for the statement subjournal*/
+  sqlite3_file *fd, *jfd;     /* File descriptors for database and journal */
+  sqlite3_file *stfd;         /* File descriptor for the statement subjournal*/
   BusyHandler *pBusyHandler;  /* Pointer to sqlite.busyHandler */
   PgHdr *pFirst, *pLast;      /* List of free pages */
   PgHdr *pFirstSynced;        /* First free page with PgHdr.needSync==0 */
@@ -526,9 +526,9 @@ static void pager_resize_hash_table(Pager *pPager, int N){
 **
 ** All values are stored on disk as big-endian.
 */
-static int read32bits(OsFile *fd, u32 *pRes){
+static int read32bits(sqlite3_file *fd, i64 offset, u32 *pRes){
   unsigned char ac[4];
-  int rc = sqlite3OsRead(fd, ac, sizeof(ac));
+  int rc = sqlite3OsRead(fd, ac, sizeof(ac), offset);
   if( rc==SQLITE_OK ){
     *pRes = sqlite3Get4byte(ac);
   }
@@ -544,10 +544,10 @@ static int read32bits(OsFile *fd, u32 *pRes){
 ** Write a 32-bit integer into the given file descriptor.  Return SQLITE_OK
 ** on success or an error code is something goes wrong.
 */
-static int write32bits(OsFile *fd, u32 val){
+static int write32bits(sqlite3_file *fd, i64 offset, u32 val){
   char ac[4];
   put32bits(ac, val);
-  return sqlite3OsWrite(fd, ac, 4);
+  return sqlite3OsWrite(fd, ac, 4, offset);
 }
 
 /*
@@ -627,7 +627,7 @@ static void checkPage(PgHdr *pPg){
 ** If no master journal file name is present *pzMaster is set to 0 and
 ** SQLITE_OK returned.
 */
-static int readMasterJournal(OsFile *pJrnl, char **pzMaster){
+static int readMasterJournal(sqlite3_file *pJrnl, char **pzMaster){
   int rc;
   u32 len;
   i64 szJ;
@@ -640,26 +640,20 @@ static int readMasterJournal(OsFile *pJrnl, char **pzMaster){
   rc = sqlite3OsFileSize(pJrnl, &szJ);
   if( rc!=SQLITE_OK || szJ<16 ) return rc;
 
-  rc = sqlite3OsSeek(pJrnl, szJ-16);
-  if( rc!=SQLITE_OK ) return rc;
-  rc = read32bits(pJrnl, &len);
+  rc = read32bits(pJrnl, szJ-16, &len);
   if( rc!=SQLITE_OK ) return rc;
 
-  rc = read32bits(pJrnl, &cksum);
+  rc = read32bits(pJrnl, szJ-12, &cksum);
   if( rc!=SQLITE_OK ) return rc;
 
-  rc = sqlite3OsRead(pJrnl, aMagic, 8);
+  rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8);
   if( rc!=SQLITE_OK || memcmp(aMagic, aJournalMagic, 8) ) return rc;
 
-  rc = sqlite3OsSeek(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 = sqlite3OsRead(pJrnl, *pzMaster, len, szJ-16-len);
   if( rc!=SQLITE_OK ){
     sqliteFree(*pzMaster);
     *pzMaster = 0;
@@ -700,7 +694,7 @@ static int readMasterJournal(OsFile *pJrnl, char **pzMaster){
 ** 2000                      2048
 ** 
 */
-static int seekJournalHdr(Pager *pPager){
+static void seekJournalHdr(Pager *pPager){
   i64 offset = 0;
   i64 c = pPager->journalOff;
   if( c ){
@@ -710,7 +704,6 @@ static int seekJournalHdr(Pager *pPager){
   assert( offset>=c );
   assert( (offset-c)<JOURNAL_HDR_SZ(pPager) );
   pPager->journalOff = offset;
-  return sqlite3OsSeek(pPager->jfd, pPager->journalOff);
 }
 
 /*
@@ -735,11 +728,8 @@ static int writeJournalHdr(Pager *pPager){
     pPager->stmtHdrOff = pPager->journalOff;
   }
 
-  rc = seekJournalHdr(pPager);
-  if( rc ) return rc;
-
+  seekJournalHdr(pPager);
   pPager->journalHdr = pPager->journalOff;
-  pPager->journalOff += JOURNAL_HDR_SZ(pPager);
 
   /* FIX ME: 
   **
@@ -760,17 +750,15 @@ static int writeJournalHdr(Pager *pPager){
   /* The assumed sector size for this process */
   put32bits(&zHeader[sizeof(aJournalMagic)+12], pPager->sectorSize);
   IOTRACE(("JHDR %p %lld %d\n", pPager, pPager->journalHdr, sizeof(zHeader)))
-  rc = sqlite3OsWrite(pPager->jfd, zHeader, sizeof(zHeader));
+  rc = sqlite3OsWrite(pPager->jfd, zHeader, sizeof(zHeader),pPager->journalOff);
+  pPager->journalOff += JOURNAL_HDR_SZ(pPager);
 
   /* The journal header has been written successfully. Seek the journal
   ** file descriptor to the end of the journal header sector.
   */
   if( rc==SQLITE_OK ){
     IOTRACE(("JTAIL %p %lld\n", pPager, pPager->journalOff-1))
-    rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff-1);
-    if( rc==SQLITE_OK ){
-      rc = sqlite3OsWrite(pPager->jfd, "\000", 1);
-    }
+    rc = sqlite3OsWrite(pPager->jfd, "\000", 1, pPager->journalOff-1);
   }
   return rc;
 }
@@ -799,28 +787,29 @@ static int readJournalHdr(
 ){
   int rc;
   unsigned char aMagic[8]; /* A buffer to hold the magic header */
+  i64 jrnlOff;
 
-  rc = seekJournalHdr(pPager);
-  if( rc ) return rc;
-
+  seekJournalHdr(pPager);
   if( pPager->journalOff+JOURNAL_HDR_SZ(pPager) > journalSize ){
     return SQLITE_DONE;
   }
+  jrnlOff = pPager->journalOff;
 
-  rc = sqlite3OsRead(pPager->jfd, aMagic, sizeof(aMagic));
+  rc = sqlite3OsRead(pPager->jfd, aMagic, sizeof(aMagic), jrnlOff);
   if( rc ) return rc;
+  jrnlOff += sizeof(aMagic);
 
   if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){
     return SQLITE_DONE;
   }
 
-  rc = read32bits(pPager->jfd, pNRec);
+  rc = read32bits(pPager->jfd, jrnlOff, pNRec);
   if( rc ) return rc;
 
-  rc = read32bits(pPager->jfd, &pPager->cksumInit);
+  rc = read32bits(pPager->jfd, jrnlOff+4, &pPager->cksumInit);
   if( rc ) return rc;
 
-  rc = read32bits(pPager->jfd, pDbSize);
+  rc = read32bits(pPager->jfd, jrnlOff+8, pDbSize);
   if( rc ) return rc;
 
   /* Update the assumed sector-size to match the value used by 
@@ -829,12 +818,11 @@ static int readJournalHdr(
   ** is being called from within pager_playback(). The local value
   ** of Pager.sectorSize is restored at the end of that routine.
   */
-  rc = read32bits(pPager->jfd, (u32 *)&pPager->sectorSize);
+  rc = read32bits(pPager->jfd, jrnlOff+12, (u32 *)&pPager->sectorSize);
   if( rc ) return rc;
 
   pPager->journalOff += JOURNAL_HDR_SZ(pPager);
-  rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff);
-  return rc;
+  return SQLITE_OK;
 }
 
 
@@ -861,6 +849,7 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
   int rc;
   int len; 
   int i; 
+  i64 jrnlOff;
   u32 cksum = 0;
   char zBuf[sizeof(aJournalMagic)+2*4];
 
@@ -877,21 +866,23 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
   ** the journal has already been synced.
   */
   if( pPager->fullSync ){
-    rc = seekJournalHdr(pPager);
-    if( rc!=SQLITE_OK ) return rc;
+    seekJournalHdr(pPager);
   }
+  jrnlOff = pPager->journalOff;
   pPager->journalOff += (len+20);
 
-  rc = write32bits(pPager->jfd, PAGER_MJ_PGNO(pPager));
+  rc = write32bits(pPager->jfd, jrnlOff, PAGER_MJ_PGNO(pPager));
   if( rc!=SQLITE_OK ) return rc;
+  jrnlOff += 4;
 
-  rc = sqlite3OsWrite(pPager->jfd, zMaster, len);
+  rc = sqlite3OsWrite(pPager->jfd, zMaster, len, jrnlOff);
   if( rc!=SQLITE_OK ) return rc;
+  jrnlOff += len;
 
   put32bits(zBuf, len);
   put32bits(&zBuf[4], cksum);
   memcpy(&zBuf[8], aJournalMagic, sizeof(aJournalMagic));
-  rc = sqlite3OsWrite(pPager->jfd, zBuf, 8+sizeof(aJournalMagic));
+  rc = sqlite3OsWrite(pPager->jfd, zBuf, 8+sizeof(aJournalMagic), jrnlOff);
   pPager->needSync = !pPager->noSync;
   return rc;
 }
@@ -1026,7 +1017,6 @@ static int pager_end_transaction(Pager *pPager){
   if( pPager->journalOpen ){
     if( pPager->exclusiveMode 
           && (rc = sqlite3OsTruncate(pPager->jfd, 0))==SQLITE_OK ){;
-      sqlite3OsSeek(pPager->jfd, 0);
       pPager->journalOff = 0;
       pPager->journalStarted = 0;
     }else{
@@ -1111,7 +1101,12 @@ static void makeClean(PgHdr*);
 ** are not used in statement journals because statement journals do not
 ** need to survive power failures.
 */
-static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
+static int pager_playback_one_page(
+  Pager *pPager, 
+  sqlite3_file *jfd,
+  i64 offset,
+  int useCksum
+){
   int rc;
   PgHdr *pPg;                   /* An existing page in the cache */
   Pgno pgno;                    /* The page number of a page in journal */
@@ -1124,9 +1119,9 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
   assert( jfd == (useCksum ? pPager->jfd : pPager->stfd) );
   assert( aData );
 
-  rc = read32bits(jfd, &pgno);
+  rc = read32bits(jfd, offset, &pgno);
   if( rc!=SQLITE_OK ) return rc;
-  rc = sqlite3OsRead(jfd, aData, pPager->pageSize);
+  rc = sqlite3OsRead(jfd, aData, pPager->pageSize, offset+4);
   if( rc!=SQLITE_OK ) return rc;
   pPager->journalOff += pPager->pageSize + 4;
 
@@ -1142,7 +1137,7 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
     return SQLITE_OK;
   }
   if( useCksum ){
-    rc = read32bits(jfd, &cksum);
+    rc = read32bits(jfd, offset+pPager->pageSize+4, &cksum);
     if( rc ) return rc;
     pPager->journalOff += 4;
     if( pager_cksum(pPager, aData)!=cksum ){
@@ -1184,10 +1179,8 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
   PAGERTRACE4("PLAYBACK %d page %d hash(%08x)\n",
                PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, aData));
   if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){
-    rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize);
-    if( rc==SQLITE_OK ){
-      rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize);
-    }
+    i64 offset = (pgno-1)*(i64)pPager->pageSize;
+    rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize, offset);
     if( pPg ){
       makeClean(pPg);
     }
@@ -1235,7 +1228,7 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
 static int pager_delmaster(const char *zMaster){
   int rc;
   int master_open = 0;
-  OsFile *master = 0;
+  sqlite3_file *master = 0;
   char *zMasterJournal = 0; /* Contents of master journal file */
   i64 nMasterJournal;       /* Size of master journal file */
 
@@ -1261,7 +1254,7 @@ static int pager_delmaster(const char *zMaster){
       rc = SQLITE_NOMEM;
       goto delmaster_out;
     }
-    rc = sqlite3OsRead(master, zMasterJournal, nMasterJournal);
+    rc = sqlite3OsRead(master, zMasterJournal, nMasterJournal, 0);
     if( rc!=SQLITE_OK ) goto delmaster_out;
 
     zJournal = zMasterJournal;
@@ -1271,7 +1264,7 @@ static int pager_delmaster(const char *zMaster){
         ** Open it and check if it points at the master journal. If
         ** so, return without deleting the master journal file.
         */
-        OsFile *journal = 0;
+        sqlite3_file *journal = 0;
         int c;
 
         rc = sqlite3OsOpenReadOnly(zJournal, &journal);
@@ -1424,7 +1417,6 @@ static int pager_playback(Pager *pPager, int isHot){
     if( rc==SQLITE_DONE ) rc = SQLITE_OK;
     goto end_playback;
   }
-  sqlite3OsSeek(pPager->jfd, 0);
   pPager->journalOff = 0;
 
   /* This loop terminates either when the readJournalHdr() call returns
@@ -1480,7 +1472,7 @@ static int pager_playback(Pager *pPager, int isHot){
     /* Copy original pages out of the journal and back into the database file.
     */
     for(i=0; i<nRec; i++){
-      rc = pager_playback_one_page(pPager, pPager->jfd, 1);
+      rc = pager_playback_one_page(pPager, pPager->jfd, pPager->journalOff, 1);
       if( rc!=SQLITE_OK ){
         if( rc==SQLITE_DONE ){
           rc = SQLITE_OK;
@@ -1567,7 +1559,6 @@ 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);
   nRec = pPager->stmtNRec;
   
   /* Copy original pages out of the statement journal and back into the
@@ -1575,8 +1566,9 @@ static int pager_stmt_playback(Pager *pPager){
   ** each record since power-failure recovery is not important to statement
   ** journals.
   */
-  for(i=nRec-1; i>=0; i--){
-    rc = pager_playback_one_page(pPager, pPager->stfd, 0);
+  for(i=0; i<nRec; i++){
+    i64 offset = i*(4+pPager->pageSize);
+    rc = pager_playback_one_page(pPager, pPager->stfd, offset, 0);
     assert( rc!=SQLITE_DONE );
     if( rc!=SQLITE_OK ) goto end_stmt_playback;
   }
@@ -1589,14 +1581,10 @@ 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);
-  if( rc!=SQLITE_OK ){
-    goto end_stmt_playback;
-  }
   pPager->journalOff = pPager->stmtJSize;
   pPager->cksumInit = pPager->stmtCksum;
   while( pPager->journalOff < hdrOff ){
-    rc = pager_playback_one_page(pPager, pPager->jfd, 1);
+    rc = pager_playback_one_page(pPager, pPager->jfd, pPager->journalOff, 1);
     assert( rc!=SQLITE_DONE );
     if( rc!=SQLITE_OK ) goto end_stmt_playback;
   }
@@ -1613,7 +1601,7 @@ static int pager_stmt_playback(Pager *pPager){
       nJRec = (szJ - pPager->journalOff) / (pPager->pageSize+8);
     }
     for(i=nJRec-1; i>=0 && pPager->journalOff < szJ; i--){
-      rc = pager_playback_one_page(pPager, pPager->jfd, 1);
+      rc = pager_playback_one_page(pPager, pPager->jfd, pPager->journalOff, 1);
       assert( rc!=SQLITE_DONE );
       if( rc!=SQLITE_OK ) goto end_stmt_playback;
     }
@@ -1693,7 +1681,7 @@ int sqlite3_opentemp_count = 0;
 ** The OS will automatically delete the temporary file when it is
 ** closed.
 */
-static int sqlite3PagerOpentemp(OsFile **pFd){
+static int sqlite3PagerOpentemp(sqlite3_file **pFd){
   int cnt = 8;
   int rc;
   char zFile[SQLITE_TEMPNAME_SIZE];
@@ -1733,7 +1721,7 @@ int sqlite3PagerOpen(
   Pager *pPager = 0;
   char *zFullPathname = 0;
   int nameLen;  /* Compiler is wrong. This is always initialized before use */
-  OsFile *fd = 0;
+  sqlite3_file *fd = 0;
   int rc = SQLITE_OK;
   int i;
   int tempFile = 0;
@@ -1970,11 +1958,8 @@ int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){
   int rc = SQLITE_OK;
   memset(pDest, 0, N);
   if( MEMDB==0 ){
-    disable_simulated_io_errors();
-    sqlite3OsSeek(pPager->fd, 0);
-    enable_simulated_io_errors();
     IOTRACE(("DBHDR %p 0 %d\n", pPager, N))
-    rc = sqlite3OsRead(pPager->fd, pDest, N);
+    rc = sqlite3OsRead(pPager->fd, pDest, N, 0);
     if( rc==SQLITE_IOERR_SHORT_READ ){
       rc = SQLITE_OK;
     }
@@ -2381,6 +2366,8 @@ static int syncJournal(Pager *pPager){
       }
 #endif
       {
+        i64 jrnlOff;
+
         /* Write the nRec value into the journal file header. If in
         ** full-synchronous mode, sync the journal first. This ensures that
         ** all data has really hit the disk before nRec is updated to mark
@@ -2392,15 +2379,10 @@ static int syncJournal(Pager *pPager){
           rc = sqlite3OsSync(pPager->jfd, 0);
           if( rc!=0 ) return rc;
         }
-        rc = sqlite3OsSeek(pPager->jfd,
-                           pPager->journalHdr + sizeof(aJournalMagic));
-        if( rc ) return rc;
-        IOTRACE(("JHDR %p %lld %d\n", pPager,
-                  pPager->journalHdr + sizeof(aJournalMagic), 4))
-        rc = write32bits(pPager->jfd, pPager->nRec);
-        if( rc ) return rc;
 
-        rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff);
+        jrnlOff = pPager->journalHdr + sizeof(aJournalMagic);
+        IOTRACE(("JHDR %p %lld %d\n", pPager, jrnlOff, 4));
+        rc = write32bits(pPager->jfd, jrnlOff, pPager->nRec);
         if( rc ) return rc;
       }
       PAGERTRACE2("SYNC journal of %d\n", PAGERID(pPager));
@@ -2545,19 +2527,18 @@ static int pager_write_pagelist(PgHdr *pList){
   pList = sort_pagelist(pList);
   while( pList ){
     assert( pList->dirty );
-    rc = sqlite3OsSeek(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 sqlite3PagerTruncate() was called to
     ** make the file smaller (presumably by auto-vacuum code). Do not write
     ** any such pages to the file.
     */
     if( pList->pgno<=pPager->dbSize ){
+      i64 offset = (pList->pgno-1)*(i64)pPager->pageSize;
       char *pData = CODEC2(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
       PAGERTRACE4("STORE %d page %d hash(%08x)\n",
                    PAGERID(pPager), pList->pgno, pager_pagehash(pList));
       IOTRACE(("PGOUT %p %d\n", pPager, pList->pgno));
-      rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize);
+      rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);
       PAGER_INCR(sqlite3_pager_writedb_count);
       PAGER_INCR(pPager->nWrite);
       if( pList->pgno==1 ){
@@ -2796,12 +2777,10 @@ int sqlite3PagerReleaseMemory(int nReq){
 */
 static int readDbPage(Pager *pPager, PgHdr *pPg, Pgno pgno){
   int rc;
+  i64 offset;
   assert( MEMDB==0 );
-  rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize);
-  if( rc==SQLITE_OK ){
-    rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg),
-                          pPager->pageSize);
-  }
+  offset = (pgno-1)*(i64)pPager->pageSize;
+  rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize, offset);
   PAGER_INCR(sqlite3_pager_readdb_count);
   PAGER_INCR(pPager->nRead);
   IOTRACE(("PGIN %p %d\n", pPager, pgno));
@@ -2934,11 +2913,7 @@ static int pagerSharedLock(Pager *pPager){
 
         if( pPager->dbSize>0 ){
           IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
-          rc = sqlite3OsSeek(pPager->fd, 24);
-          if( rc!=SQLITE_OK ){
-            return rc;
-          }
-          rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers));
+          rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
           if( rc!=SQLITE_OK ){
             return rc;
           }
@@ -3332,9 +3307,11 @@ static int pager_open_journal(Pager *pPager){
     }
     goto failed_to_open_journal;
   }
+#if 0
   sqlite3OsSetFullSync(pPager->jfd, pPager->full_fsync);
   sqlite3OsSetFullSync(pPager->fd, pPager->full_fsync);
   sqlite3OsOpenDirectory(pPager->jfd, pPager->zDirectory);
+#endif
   pPager->journalOpen = 1;
   pPager->journalStarted = 0;
   pPager->needSync = 0;
@@ -3583,7 +3560,7 @@ static int pager_write(PgHdr *pPg){
           put32bits(pEnd, cksum);
           szPg = pPager->pageSize+8;
           put32bits(pData2, pPg->pgno);
-          rc = sqlite3OsWrite(pPager->jfd, pData2, szPg);
+          rc = sqlite3OsWrite(pPager->jfd, pData2, szPg, pPager->journalOff);
           IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno,
                    pPager->journalOff, szPg));
           PAGER_INCR(sqlite3_pager_writej_count);
@@ -3638,9 +3615,10 @@ static int pager_write(PgHdr *pPg){
         PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
         page_add_to_stmt_list(pPg);
       }else{
+        i64 offset = pPager->stmtNRec*(4+pPager->pageSize);
         char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7)-4;
         put32bits(pData2, pPg->pgno);
-        rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize+4);
+        rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize+4, offset);
         PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
         if( rc!=SQLITE_OK ){
           return rc;
@@ -4215,7 +4193,6 @@ int sqlite3PagerStmtCommit(Pager *pPager){
     PgHdr *pPg, *pNext;
     PAGERTRACE2("STMT-COMMIT %d\n", PAGERID(pPager));
     if( !MEMDB ){
-      sqlite3OsSeek(pPager->stfd, 0);
       /* sqlite3OsTruncate(pPager->stfd, 0); */
       sqliteFree( pPager->aInStmt );
       pPager->aInStmt = 0;
index c614201cf8589c1312b04fd5bccb030499b7a17b..d378ed076c183e4b402e1e242debe13720f5bada 100644 (file)
@@ -30,7 +30,7 @@
 ** the version number) and changes its name to "sqlite3.h" as
 ** part of the build process.
 **
-** @(#) $Id: sqlite.h.in,v 1.223 2007/08/15 13:04:54 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.224 2007/08/15 17:08:46 danielk1977 Exp $
 */
 #ifndef _SQLITE3_H_
 #define _SQLITE3_H_
@@ -488,7 +488,7 @@ struct sqlite3_io_methods {
   int iVersion;
   int (*xClose)(sqlite3_file*);
   int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite_int64 iOfst);
-  int (*xWrite)(sqlite3_file*, void*, int iAmt, sqlite_int64 iOfst);
+  int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite_int64 iOfst);
   int (*xTruncate)(sqlite3_file*, sqlite_int64 size);
   int (*xSync)(sqlite3_file*, int flags);
   int (*xFileSize)(sqlite3_file*, sqlite_int64 *pSize);
index 1398c183793ba53ca5c709e43effac2231b9c846..540957e348180a88d1d27b9fce3738f606e99cd6 100644 (file)
@@ -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.43 2007/04/02 05:07:47 danielk1977 Exp $
+** $Id: test2.c,v 1.44 2007/08/15 17:08:46 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -546,12 +546,7 @@ static int fake_big_file(
   }
   offset = n;
   offset *= 1024*1024;
-  rc = sqlite3OsSeek(fd, offset);
-  if( rc ){
-    Tcl_AppendResult(interp, "seek failed: ", errorName(rc), 0);
-    return TCL_ERROR;
-  }
-  rc = sqlite3OsWrite(fd, "Hello, World!", 14);
+  rc = sqlite3OsWrite(fd, "Hello, World!", 14, offset);
   sqlite3OsClose(&fd);
   if( rc ){
     Tcl_AppendResult(interp, "write failed: ", errorName(rc), 0);
index 5b49156daf74dc8a3550f26b0177a20b3e96f952..534a09f1b068b6caaec8d8a427367d6c5d9f0041 100644 (file)
@@ -21,7 +21,8 @@
 
 #ifndef SQLITE_OMIT_DISKIO  /* This file is a no-op if disk I/O is disabled */
 
-typedef struct crashFile crashFile;
+typedef struct CrashFile CrashFile;
+typedef struct CrashGlobal CrashGlobal;
 typedef struct WriteBuffer WriteBuffer;
 
 /*
@@ -103,523 +104,429 @@ typedef struct WriteBuffer WriteBuffer;
 **   operation is one byte past the current end of the file, then option
 **   (1) is always selected.
 */
-struct WriteBuffer {
-  i64 iOffset;             /* Byte offset of the start of this write() */
-  int nBuf;                /* Number of bytes written */
-  u8 *zBuf;                /* Pointer to copy of written data */
-  crashFile *pFile;        /* File this write() applies to */
-};
 
 /*
-** crashFile is a subclass of OsFile that is taylored for 
-** the crash test module.
+** Each write operation in the write-list is represented by an instance
+** of the following structure.
+**
+** If zBuf is 0, then this structure represents a call to xTruncate(), 
+** not xWrite(). In that case, iOffset is the size that the file is
+** truncated to.
 */
-struct crashFile {
-  IoMethod const *pMethod; /* Must be first */
-  u8 **apBlk;              /* Array of blocks that have been written to. */
-  int nBlk;                /* Size of apBlock. */
-  i64 offset;              /* Next character to be read from the file */
-  int nMaxWrite;           /* Largest offset written to. */
-  char *zName;             /* File name */
-  OsFile *pBase;           /* The real file */
-  crashFile *pNext;        /* Next in a list of them all */
-};
+struct WriteBuffer {
+  i64 iOffset;                 /* Byte offset of the start of this write() */
+  int nBuf;                    /* Number of bytes written */
+  u8 *zBuf;                    /* Pointer to copy of written data */
+  CrashFile *pFile;            /* File this write() applies to */
 
-/*
-** Size of a simulated disk block. Default is 512 bytes.
-*/
-static int BLOCKSIZE = 512;
-#define BLOCK_OFFSET(x) ((x) * BLOCKSIZE)
+  WriteBuffer *pNext;          /* Next in CrashGlobal.pWriteList */
+};
 
+struct CrashFile {
+  const sqlite3_io_methods *pMethod;   /* Must be first */
+  sqlite3_file *pRealFile;             /* Underlying "real" file handle */
+  const char *zName;
+};
 
-/*
-** 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];
+struct CrashGlobal {
+  WriteBuffer *pWriteList;     /* Head of write-list */
 
-/*
-** A list of all open files.
-*/
-static crashFile *pAllFiles = 0;
+  int iSectorSize;             /* Value of simulated sector size */
+  int iDeviceCharacteristics;  /* Value of simulated device characteristics */
 
-/*
-** 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();
-}
+  int iCrash;                  /* Crash on the iCrash'th call to xSync() */
+  char zCrashFile[500];        /* Crash during an xSync() on this file */ 
+};
 
-/*
-** Set the value of the simulated disk block size.
-*/
-static void setBlocksize(int iBlockSize){
-  sqlite3OsEnterMutex();
-  assert( !pAllFiles );
-  BLOCKSIZE = iBlockSize;
-  sqlite3OsLeaveMutex();
-}
+static CrashGlobal g = {0, SQLITE_DEFAULT_SECTOR_SIZE, 0, 0};
 
 /*
-** File zPath is being sync()ed. Return non-zero if this should
-** cause a crash.
+** Set this global variable to 1 to enable crash testing.
 */
-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;
-}
-
-/* Forward reference */
-static void initFile(OsFile **pId, char const *zName, OsFile *pBase);
+int sqlite3CrashTestEnable = 0;
 
 /*
-** Undo the work done by initFile. Delete the OsFile structure
-** and unlink the structure from the pAllFiles list.
+** Flush the write-list as if xSync() had been called on file handle
+** pFile. If isCrash is true, simulate a crash.
 */
-static void closeFile(crashFile **pId){
-  crashFile *pFile = *pId;
-  if( pFile==pAllFiles ){
-    pAllFiles = pFile->pNext;
-  }else{
-    crashFile *p;
-    for(p=pAllFiles; p->pNext!=pFile; p=p->pNext ){
-      assert( p );
+static int writeListSync(CrashFile *pFile, int isCrash){
+  int rc = SQLITE_OK;
+  int iDc = g.iDeviceCharacteristics;
+
+  WriteBuffer *pWrite;
+  WriteBuffer **ppPtr;
+
+  /* Set pFinal to point to the last element of the write-list that
+  ** is associated with file handle pFile.
+  */
+  WriteBuffer *pFinal = 0;
+  if( !isCrash ){
+    for(pWrite=g.pWriteList; pWrite; pWrite=pWrite->pNext){
+      if( pWrite->pFile==pFile ){
+        pFinal = pWrite;
+      }
     }
-    p->pNext = pFile->pNext;
-  }
-  sqliteFree(*pId);
-  *pId = 0;
-}
-
-/*
-** Read block 'blk' off of the real disk file and into the cache of pFile.
-*/
-static int readBlockIntoCache(crashFile *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;
+  ppPtr = &g.pWriteList;
+  for(pWrite=*ppPtr; rc==SQLITE_OK && pWrite; pWrite=*ppPtr){
+
+    /* (eAction==1)      -> write block out normally,
+    ** (eAction==2)      -> do nothing,
+    ** (eAction==3)      -> trash sectors.
+    */
+    int eAction = 0;
+    if( !isCrash ){
+      eAction = 2;
+      if( (pWrite->pFile==pFile || iDc&SQLITE_IOCAP_SEQUENTIAL) ){
+        eAction = 1;
+      }
+    }else{
+      char random;
+      sqlite3Randomness(1, &random);
 
-    rc = sqlite3OsFileSize(pFile->pBase, &filesize);
-    if( rc!=SQLITE_OK ) return rc;
+      if( iDc&SQLITE_IOCAP_ATOMIC || pWrite->zBuf==0 ){
+        random &= 0x01;
+      }
 
-    if( BLOCK_OFFSET(blk)<filesize ){
-      int len = BLOCKSIZE;
-      rc = sqlite3OsSeek(pFile->pBase, blk*BLOCKSIZE);
-      if( BLOCK_OFFSET(blk+1)>filesize ){
-        len = filesize - BLOCK_OFFSET(blk);
+      if( (random&0x06)==0x06 ){
+        eAction = 3;
+      }else{
+        eAction = ((random&0x01)?2:1);
       }
-      if( rc!=SQLITE_OK ) return rc;
-      rc = sqlite3OsRead(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(crashFile *pFile, int crash){
-  int i;
-  int nMax = pFile->nMaxWrite;
-  int rc = SQLITE_OK;
-
-  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
-          }
+    switch( eAction ){
+      case 1: {               /* Write out correctly */
+        if( pWrite->zBuf ){
+          rc = sqlite3OsWrite(
+              pFile->pRealFile, pWrite->zBuf, pWrite->nBuf, pWrite->iOffset
+          );
         }else{
-#ifdef TRACE_WRITECACHE
-printf("Writing block %d of %s\n", i, pFile->zName); 
-#endif
+          rc = sqlite3OsTruncate(pFile->pRealFile, pWrite->iOffset);
         }
+        *ppPtr = pWrite->pNext;
+        sqliteFree(pWrite);
+        break;
       }
-      if( rc==SQLITE_OK ){
-        rc = sqlite3OsSeek(pFile->pBase, BLOCK_OFFSET(i));
+      case 2: {               /* Do nothing */
+        ppPtr = &pWrite->pNext;
+        break;
       }
-      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);
+      case 3: {               /* Trash sectors */
+        u8 *zGarbage;
+        sqlite3_int64 iFirst = (pWrite->iOffset%g.iSectorSize);
+        sqlite3_int64 iLast = (pWrite->iOffset+pWrite->nBuf-1)%g.iSectorSize;
+
+        zGarbage = sqliteMalloc(g.iSectorSize);
+        if( zGarbage ){
+          sqlite3_int64 i;
+          for(i=iFirst; rc==SQLITE_OK && i<=iLast; i++){
+            sqlite3Randomness(g.iSectorSize, zGarbage); 
+            rc = sqlite3OsWrite(
+              pFile->pRealFile, i*g.iSectorSize, zGarbage, g.iSectorSize
+            );
           }
-          rc = sqlite3OsWrite(pFile->pBase, p, len);
+          sqliteFree(zGarbage);
+        }else{
+          rc = SQLITE_NOMEM;
         }
+
+        ppPtr = &pWrite->pNext;
+        break;
       }
-      sqliteFree(p);
+
+      default:
+        assert(!"Cannot happen");
     }
+
+    if( pWrite==pFinal ) break;
+  }
+
+  if( rc==SQLITE_OK && isCrash ){
+    exit(-1);
   }
-  sqliteFree(pFile->apBlk);
-  pFile->nBlk = 0;
-  pFile->apBlk = 0;
-  pFile->nMaxWrite = 0;
+
   return rc;
 }
 
 /*
-** Write the cache to disk.
+** Add an entry to the end of the write-list.
 */
-static int writeCache(crashFile *pFile){
-  if( pFile->apBlk ){
-    int c = crashRequired(pFile->zName);
-    if( c ){
-      crashFile *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);
-    }
+static int writeListAppend(
+  sqlite3_file *pFile,
+  sqlite3_int64 iOffset,
+  const u8 *zBuf,
+  int nBuf
+){
+  WriteBuffer *pNew;
+
+  assert((zBuf && nBuf) || (!nBuf && !zBuf));
+
+  pNew = (WriteBuffer *)sqliteMalloc(sizeof(WriteBuffer) + nBuf);
+  pNew->iOffset = iOffset;
+  pNew->nBuf = nBuf;
+  pNew->pFile = (CrashFile *)pFile;
+  if( zBuf ){
+    pNew->zBuf = (u8 *)&pNew[1];
+    memcpy(pNew->zBuf, zBuf, nBuf);
   }
-  return SQLITE_OK;
-}
 
-/*
-** Close the file.
-*/
-static int crashClose(OsFile **pId){
-  crashFile *pFile = (crashFile*)*pId;
-  if( pFile ){
-    /* printf("CLOSE %s (%d blocks)\n", pFile->zName, pFile->nBlk); */
-    writeCache(pFile);
-    sqlite3OsClose(&pFile->pBase);
+  if( g.pWriteList ){
+    WriteBuffer *pEnd;
+    for(pEnd=g.pWriteList; pEnd->pNext; pEnd=pEnd->pNext);
+    pEnd->pNext = pNew;
+  }else{
+    g.pWriteList = pNew;
   }
-  closeFile(&pFile);
-  *pId = 0;
+  
   return SQLITE_OK;
 }
 
-static int crashSeek(OsFile *id, i64 offset){
-  ((crashFile*)id)->offset = offset;
+/*
+** Close a crash-file.
+*/
+int cfClose(sqlite3_file *pFile){
+  CrashFile *pCrash = (CrashFile *)pFile;
+  writeListSync(pCrash, 0);
+  sqlite3OsClose(&pCrash->pRealFile);
   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;
-  crashFile *pFile = (crashFile*)id;
-
-  offset = pFile->offset;
-  end = offset+amt;
-  blk = (offset/BLOCKSIZE);
+/*
+** Read data from a crash-file.
+*/
+int cfRead(sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst){
+  CrashFile *pCrash = (CrashFile *)pFile;
+  sqlite3_int64 iSize;
+  int rc;
+  WriteBuffer *pWrite;
 
-  zCsr = (u8 *)pBuf;
-  for(i=blk; i*BLOCKSIZE<end; i++){
-    int off = 0;
-    int len = 0;
+  /* Check the file-size to see if this is a short-read */
+  rc = sqlite3OsFileSize(pFile, &iSize);
+  if( rc!=SQLITE_OK ){
+    return rc;
+  }
+  if( iSize<(iOfst+iAmt) ){
+    return SQLITE_IOERR_SHORT_READ;
+  }
 
+  /* Zero the output buffer */
+  memset(zBuf, 0, iAmt);
 
-    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);
+  /* Read some data from the real file */
+  rc = sqlite3OsFileSize(pCrash->pRealFile, &iSize);
+  if( rc==SQLITE_OK && iSize>iOfst ){
+    int nRead = iAmt;
+    if( iSize<(iOfst+iAmt) ){
+      nRead = iSize - iOfst;
     }
-
-    if( i<pFile->nBlk && pFile->apBlk[i]){
-      u8 *pBlk = pFile->apBlk[i];
-      memcpy(zCsr, &pBlk[off], len);
-    }else{
-      rc = sqlite3OsSeek(pFile->pBase, BLOCK_OFFSET(i) + off);
-      if( rc!=SQLITE_OK ) return rc;
-      rc = sqlite3OsRead(pFile->pBase, zCsr, len);
-      if( rc!=SQLITE_OK ) return rc;
-    }
-
-    zCsr += len;
+    rc = sqlite3OsRead(pCrash->pRealFile, zBuf, nRead, iOfst);
   }
-  assert( zCsr==&((u8 *)pBuf)[amt] );
-
-  pFile->offset = 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;
-  crashFile *pFile = (crashFile*)id;
-
-  offset = pFile->offset;
-  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 = readBlockIntoCache(pFile, i);
-    if( rc!=SQLITE_OK ) return rc;
 
-    /* Write into the cache */
-    pBlk = pFile->apBlk[i];
-    assert( pBlk );
+  /* Fill in the buffer by traversing the write-list */
+  for(pWrite=g.pWriteList; rc==SQLITE_OK && pWrite; pWrite=pWrite->pNext){
+    if( pWrite->pFile==pCrash ){
+      int iWriteOffset;
+      int nWriteBuf;
+      u8 *zWriteBuf;
+
+      iWriteOffset = pWrite->iOffset - iOfst;
+      nWriteBuf = pWrite->nBuf;
+      zWriteBuf = pWrite->zBuf;
+      if( iWriteOffset<0 ){
+        nWriteBuf += iWriteOffset;
+        zWriteBuf -= iWriteOffset;
+        iWriteOffset = 0;
+      }
+      if( (iWriteOffset+nWriteBuf)>iAmt ){
+        nWriteBuf = iAmt - iWriteOffset;
+      }
+      
+      if( pWrite->zBuf && nWriteBuf>0){
+        /* Copy data to the buffer */
+        memcpy(&((u8 *)zBuf)[iWriteOffset], zWriteBuf, nWriteBuf);
+      }
 
-    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( pWrite->zBuf==0 && iWriteOffset<iAmt ){
+        /* Zero part of the buffer to simulate a truncate */
+        memset(&((u8 *)zBuf)[iWriteOffset], 0, iAmt-iWriteOffset);
+      }
     }
-    memcpy(&pBlk[off], zCsr, len);
-    zCsr += len;
-  }
-  if( pFile->nMaxWrite<end ){
-    pFile->nMaxWrite = end;
   }
-  assert( zCsr==&((u8 *)pBuf)[amt] );
-  pFile->offset = end;
+
   return rc;
 }
 
 /*
-** Sync the file. First flush the write-cache to disk, then call the
-** real sync() function.
+** Write data to a crash-file.
 */
-static int crashSync(OsFile *id, int dataOnly){
-  return writeCache((crashFile*)id);
+int cfWrite(sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst){
+  return writeListAppend(pFile, iOfst, zBuf, iAmt);
 }
 
 /*
-** 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.
+** Truncate a crash-file.
 */
-static int crashTruncate(OsFile *id, i64 nByte){
-  crashFile *pFile = (crashFile*)id;
-  pFile->nMaxWrite = nByte;
-  return sqlite3OsTruncate(pFile->pBase, nByte);
+int cfTruncate(sqlite3_file *pFile, sqlite_int64 size){
+  return writeListAppend(pFile, size, 0, 0);
 }
 
 /*
-** 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.
+** Sync a crash-file.
 */
-static int crashFileSize(OsFile *id, i64 *pSize){
-  crashFile *pFile = (crashFile*)id;
-  int rc = sqlite3OsFileSize(pFile->pBase, pSize);
-  if( rc==SQLITE_OK && pSize && *pSize<pFile->nMaxWrite ){
-    *pSize = pFile->nMaxWrite;
+int cfSync(sqlite3_file *pFile, int flags){
+  CrashFile *pCrash = (CrashFile *)pFile;
+  int isCrash = 0;
+
+  if( 0==strcmp(pCrash->zName, g.zCrashFile) ){
+    if( (--g.iCrash==0) ){
+      isCrash = 1;
+    }
   }
-  return rc;
-}
 
-/*
-** Set this global variable to 1 to enable crash testing.
-*/
-int sqlite3CrashTestEnable = 0;
+  return writeListSync(pCrash, isCrash);
+}
 
 /*
-** 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.
+** Return the current file-size of the crash-file.
 */
-int sqlite3CrashOpenReadWrite(const char *zFilename, OsFile **pId,int *pRdonly){
-  OsFile *pBase = 0;
+int cfFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
+  CrashFile *pCrash = (CrashFile *)pFile;
+  WriteBuffer *pWrite;
   int rc;
+  sqlite_int64 iSize;
 
-  sqlite3CrashTestEnable = 0;
-  rc = sqlite3OsOpenReadWrite(zFilename, &pBase, pRdonly);
-  sqlite3CrashTestEnable = 1;
-  if( !rc ){
-    initFile(pId, zFilename, pBase);
+  rc = sqlite3OsFileSize(pCrash->pRealFile, &iSize);
+  if( rc!=SQLITE_OK ){
+    return rc;
   }
-  return rc;
-}
-int sqlite3CrashOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
-  OsFile *pBase = 0;
-  int rc;
 
-  sqlite3CrashTestEnable = 0;
-  rc = sqlite3OsOpenExclusive(zFilename, &pBase, delFlag);
-  sqlite3CrashTestEnable = 1;
-  if( !rc ){
-    initFile(pId, zFilename, pBase);
-  }
-  return rc;
-}
-int sqlite3CrashOpenReadOnly(const char *zFilename, OsFile **pId, int NotUsed){
-  OsFile *pBase = 0;
-  int rc;
-
-  sqlite3CrashTestEnable = 0;
-  rc = sqlite3OsOpenReadOnly(zFilename, &pBase);
-  sqlite3CrashTestEnable = 1;
-  if( !rc ){
-    initFile(pId, zFilename, pBase);
+  for(pWrite=g.pWriteList; pWrite; pWrite=pWrite->pNext){
+    sqlite_int64 iEnd = pWrite->nBuf+pWrite->iOffset;
+    if( pWrite->pFile==pCrash && (pWrite->zBuf==0 || iEnd>iSize) ){
+      iSize = iEnd;
+    }
   }
-  return rc;
-}
+  *pSize = iSize;
 
-/*
-** OpenDirectory is a no-op
-*/
-static int crashOpenDir(OsFile *id, const char *zName){
   return SQLITE_OK;
 }
 
 /*
-** Locking primitives are passed through into the underlying
-** file descriptor.
+** Calls related to file-locks are passed on to the real file handle.
 */
-int crashLock(OsFile *id, int lockType){
-  return sqlite3OsLock(((crashFile*)id)->pBase, lockType);
+int cfLock(sqlite3_file *pFile, int eLock){
+  return sqlite3OsLock(((CrashFile *)pFile)->pRealFile, eLock);
 }
-int crashUnlock(OsFile *id, int lockType){
-  return sqlite3OsUnlock(((crashFile*)id)->pBase, lockType);
+int cfUnlock(sqlite3_file *pFile, int eLock){
+  return sqlite3OsUnlock(((CrashFile *)pFile)->pRealFile, eLock);
 }
-int crashCheckReservedLock(OsFile *id){
-  return sqlite3OsCheckReservedLock(((crashFile*)id)->pBase);
+int cfCheckReservedLock(sqlite3_file *pFile){
+  return sqlite3OsCheckReservedLock(((CrashFile *)pFile)->pRealFile);
 }
-void crashSetFullSync(OsFile *id, int setting){
-  return;  /* This is a no-op */
-}
-int crashLockState(OsFile *id){
-  return sqlite3OsLockState(((crashFile*)id)->pBase);
+int cfBreakLock(sqlite3_file *pFile){
+  return sqlite3OsBreakLock(((CrashFile *)pFile)->pRealFile);
 }
 
 /*
-** Return the underlying file handle.
+** The xSectorSize() and xDeviceCharacteristics() functions return
+** the global values configured by the [sqlite_crashparams] tcl
+*  interface.
 */
-int crashFileHandle(OsFile *id){
-#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
-  return sqlite3OsFileHandle(((crashFile*)id)->pBase);
-#endif
-  return 0;
+int cfSectorSize(sqlite3_file *pFile){
+  return g.iSectorSize;
+}
+int cfDeviceCharacteristics(sqlite3_file *pFile){
+  return g.iDeviceCharacteristics;
 }
 
+static const sqlite3_io_methods CrashFileVtab = {
+  1,                            /* iVersion */
+  cfClose,                      /* xClose */
+  cfRead,                       /* xRead */
+  cfWrite,                      /* xWrite */
+  cfTruncate,                   /* xTruncate */
+  cfSync,                       /* xSync */
+  cfFileSize,                   /* xFileSize */
+  cfLock,                       /* xLock */
+  cfUnlock,                     /* xUnlock */
+  cfCheckReservedLock,          /* xCheckReservedLock */
+  cfBreakLock,                  /* xBreakLock */
+  cfSectorSize,                 /* xSectorSize */
+  cfDeviceCharacteristics       /* xDeviceCharacteristics */
+};
+
 /*
-** Return the simulated file-system sector size.
+** Open a crash-file file handle. The vfs pVfs is used to open
+** the underlying real file.
 */
-int crashSectorSize(OsFile *id){
-  return BLOCKSIZE;
+int sqlite3CrashFileOpen(
+  sqlite3_vfs *pVfs,
+  const char *zName,
+  sqlite3_file *pFile,
+  int flags,
+  int *pOutFlags
+){
+  CrashFile *pWrapper = (CrashFile *)pFile;
+  int rc = SQLITE_NOMEM;
+  sqlite3_file *pReal;
+  pReal = (sqlite3_file *)sqliteMalloc(pVfs->szOsFile);
+  if( pReal ){
+    pWrapper->pMethod = &CrashFileVtab;
+    pWrapper->zName = zName;
+    rc = pVfs->xOpen(pVfs->pAppData, zName, pReal, flags, pOutFlags);
+    if( rc==SQLITE_OK ){
+      pWrapper->pRealFile = pFile;
+    }else{
+      sqliteFree(pReal);
+    }
+  }
+  return rc;
 }
 
-/*
-** This vector defines all the methods that can operate on an OsFile
-** for the crash tester.
-*/
-static const IoMethod crashIoMethod = {
-  crashClose,
-  crashOpenDir,
-  crashRead,
-  crashWrite,
-  crashSeek,
-  crashTruncate,
-  crashSync,
-  crashSetFullSync,
-  crashFileHandle,
-  crashFileSize,
-  crashLock,
-  crashUnlock,
-  crashLockState,
-  crashCheckReservedLock,
-  crashSectorSize,
-};
+int sqlite3CrashFileWrap(
+  sqlite3_file *pFile,
+  const char *zName,
+  sqlite3_file **ppWrapper
+){
+  CrashFile *pWrapper;
+  pWrapper = (CrashFile *)sqliteMalloc(sizeof(CrashFile)+strlen(zName)+1);
+  if( !pWrapper ){
+    return SQLITE_NOMEM;
+  }
 
+  pWrapper->pMethod = &CrashFileVtab;
+  pWrapper->pRealFile = pFile;
+  pWrapper->zName = &pWrapper[1];
+  memcpy(pWrapper->zName, zName, strlen(zName)+1);
 
-/*
-** Initialise the os_test.c specific fields of pFile.
-*/
-static void initFile(OsFile **pId, char const *zName, OsFile *pBase){
-  crashFile *pFile = sqliteMalloc(sizeof(crashFile) + strlen(zName)+1);
-  pFile->pMethod = &crashIoMethod;
-  pFile->nMaxWrite = 0; 
-  pFile->offset = 0;
-  pFile->nBlk = 0; 
-  pFile->apBlk = 0; 
-  pFile->zName = (char *)(&pFile[1]);
-  strcpy(pFile->zName, zName);
-  pFile->pBase = pBase;
-  pFile->pNext = pAllFiles;
-  pAllFiles = pFile;
-  *pId = (OsFile*)pFile;
+  *ppWrapper = (sqlite3_file *)pWrapper;
+  return SQLITE_OK;
 }
 
 
+int sqlite3CrashFileSize(){
+  return (int)sizeof(CrashFile);
+}
+
 /*
-** tclcmd:   sqlite_crashparams DELAY CRASHFILE ?BLOCKSIZE?
+** tclcmd:   sqlite_crashparams ?OPTIONS? DELAY CRASHFILE
 **
 ** This procedure implements a TCL command that enables crash testing
 ** in testfixture.  Once enabled, crash testing cannot be disabled.
+**
+** Available options are "-characteristics" and "-sectorsize". Both require
+** an argument. For -sectorsize, this is the simulated sector size in
+** bytes. For -characteristics, the argument must be a list of io-capability
+** flags to simulate. Valid flags are "atomic", "atomic512", "atomic1K",
+** "atomic2K", "atomic4K", "atomic8K", "atomic16K", "atomic32K", 
+** "atomic64K", "sequential" and "safe_append".
+**
+** Example:
+**
+**   sqlite_crashparams -sect 1024 -char {atomic sequential} ./test.db 1
+**
 */
 static int crashParamsObjCmd(
   void * clientData,
@@ -627,31 +534,110 @@ static int crashParamsObjCmd(
   int objc,
   Tcl_Obj *CONST objv[]
 ){
+  int i;
+
   int iDelay;
-  const char *zFile;
-  int nFile;
+  const char *zCrashFile;
+  int nCrashFile;
+
+  int iDc = 0;
+  int iSectorSize = 0;
+  int setSectorsize = 0;
+  int setDeviceChar = 0;
+
+  struct DeviceFlag {
+    char *zName;
+    int iValue;
+  } aFlag[] = {
+    { "atomic",      SQLITE_IOCAP_ATOMIC      },
+    { "atomic512",   SQLITE_IOCAP_ATOMIC512   },
+    { "atomic1k",    SQLITE_IOCAP_ATOMIC1K    },
+    { "atomic2k",    SQLITE_IOCAP_ATOMIC2K    },
+    { "atomic4k",    SQLITE_IOCAP_ATOMIC4K    },
+    { "atomic8k",    SQLITE_IOCAP_ATOMIC8K    },
+    { "atomic16k",   SQLITE_IOCAP_ATOMIC16K   },
+    { "atomic32k",   SQLITE_IOCAP_ATOMIC32K   },
+    { "atomic64k",   SQLITE_IOCAP_ATOMIC64K   },
+    { "sequential",  SQLITE_IOCAP_SEQUENTIAL  },
+    { "safe_append", SQLITE_IOCAP_SAFE_APPEND },
+    { 0, 0 }
+  };
+  
+  if( objc<3 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "?OPTIONS? DELAY CRASHFILE");
+    return TCL_ERROR;
+  }
 
-  if( objc!=3 && objc!=4 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "DELAY CRASHFILE ?BLOCKSIZE?");
+  zCrashFile = sqlite3OsFullPathname(Tcl_GetString(objv[objc-1]));
+  nCrashFile = strlen(zCrashFile);
+  if( nCrashFile>=sizeof(g.zCrashFile) ){
+    Tcl_AppendResult(interp, "Filename is too long: \"", zCrashFile, "\"", 0);
     return TCL_ERROR;
   }
-  if( Tcl_GetIntFromObj(interp, objv[1], &iDelay) ) return TCL_ERROR;
-  zFile = Tcl_GetStringFromObj(objv[2], &nFile);
-  if( nFile>=sizeof(zCrashFile)-1 ){
-    Tcl_AppendResult(interp, "crash file name too big", 0);
+  if( Tcl_GetIntFromObj(interp, objv[objc-2], &iDelay) ){
     return TCL_ERROR;
   }
-  setCrashParams(iDelay, zFile);
-  if( objc==4 ){
-    int iBlockSize = 0;
-    if( Tcl_GetIntFromObj(interp, objv[3], &iBlockSize) ) return TCL_ERROR;
-    if( pAllFiles ){
-      char *zErr = "Cannot modify blocksize after opening files";
-      Tcl_SetResult(interp, zErr, TCL_STATIC);
+
+  for(i=1; i<(objc-2); i+=2){
+    int nOpt;
+    char *zOpt = Tcl_GetStringFromObj(objv[i], &nOpt);
+
+    if( (nOpt>11 || nOpt<2 || strncmp("-sectorsize", zOpt, nOpt)) 
+     && (nOpt>16 || nOpt<2 || strncmp("-characteristics", zOpt, nOpt))
+    ){
+      Tcl_AppendResult(interp, 
+        "Bad option: \"", zOpt, 
+        "\" - must be \"-characteristics\" or \"-sectorsize\"", 0
+      );
+      return TCL_ERROR;
+    }
+    if( i==objc-3 ){
+      Tcl_AppendResult(interp, "Option requires an argument: \"", zOpt, "\"",0);
       return TCL_ERROR;
     }
-    setBlocksize(iBlockSize);
+
+    if( zOpt[1]=='s' ){
+      if( Tcl_GetIntFromObj(interp, objv[i+1], &iSectorSize) ){
+        return TCL_ERROR;
+      }
+      setSectorsize = 1;
+    }else{
+      int j;
+      Tcl_Obj **apObj;
+      int nObj;
+      if( Tcl_ListObjGetElements(interp, objv[i+1], &nObj, &apObj) ){
+        return TCL_ERROR;
+      }
+      for(j=0; j<nObj; j++){
+        int rc;
+        int iChoice;
+        Tcl_Obj *pFlag = Tcl_DuplicateObj(apObj[j]);
+        Tcl_IncrRefCount(pFlag);
+        Tcl_UtfToLower(Tcl_GetString(pFlag));
+        rc = Tcl_GetIndexFromObjStruct(
+            interp, pFlag, aFlag, sizeof(aFlag[0]), "no such flag", 0, &iChoice
+        );
+        Tcl_DecrRefCount(pFlag);
+        if( rc ){
+          return TCL_ERROR;
+        }
+
+        iDc |= aFlag[iChoice].iValue;
+      }
+      setDeviceChar = 1;
+    }
+  }
+
+  if( setDeviceChar ){
+    g.iDeviceCharacteristics = iDc;
   }
+  if( setSectorsize ){
+    g.iSectorSize = iSectorSize;
+  }
+  g.iCrash = iDelay;
+  memcpy(g.zCrashFile, zCrashFile, nCrashFile+1);
+
   sqlite3CrashTestEnable = 1;
   return TCL_OK;
 }
index d949448052682827379d16419b930afc611af136..f7d3066be049b17cae5f0fddb3496f79a0cc7259 100644 (file)
@@ -1129,7 +1129,8 @@ static int vdbeCommit(sqlite3 *db){
     int needSync = 0;
     char *zMaster = 0;   /* File-name for the master journal */
     char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);
-    OsFile *master = 0;
+    sqlite3_file *master = 0;
+    i64 offset = 0;
 
     /* Select a master journal file name */
     do {
@@ -1164,7 +1165,8 @@ static int vdbeCommit(sqlite3 *db){
         if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){
           needSync = 1;
         }
-        rc = sqlite3OsWrite(master, zFile, strlen(zFile)+1);
+        rc = sqlite3OsWrite(master, zFile, strlen(zFile)+1, offset);
+        offset += strlen(zFile)+1;
         if( rc!=SQLITE_OK ){
           sqlite3OsClose(&master);
           sqlite3OsDelete(zMaster);
@@ -1179,6 +1181,7 @@ static int vdbeCommit(sqlite3 *db){
     ** the master journal file is store in so that it gets synced too.
     */
     zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);
+#if 0
     rc = sqlite3OsOpenDirectory(master, zMainFile);
     if( rc!=SQLITE_OK ||
           (needSync && (rc=sqlite3OsSync(master,0))!=SQLITE_OK) ){
@@ -1187,6 +1190,7 @@ static int vdbeCommit(sqlite3 *db){
       sqliteFree(zMaster);
       return rc;
     }
+#endif
 
     /* Sync all the db files involved in the transaction. The same call
     ** sets the master journal pointer in each individual journal. If