]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Pull in all the latest changes from the trunk. wal-win32
authordrh <drh@noemail.net>
Fri, 14 May 2010 16:34:34 +0000 (16:34 +0000)
committerdrh <drh@noemail.net>
Fri, 14 May 2010 16:34:34 +0000 (16:34 +0000)
Update the win32 SHM methods to work with the new interface design.

FossilOrigin-Name: 4b69f2cd315b6b66d10e5190d235114788853258

1  2 
manifest
manifest.uuid
src/os_win.c

diff --cc manifest
index 2bdebe33df6d0195102609fad17fae0761b287b1,22d9593528375d76db43ecefc17a39d045d11346..bdd18c520ae62256d566f9f9f8171db4d7968876
+++ b/manifest
@@@ -1,5 -1,8 +1,8 @@@
- C Updates\sto\sWAL\ssupport\sin\sos_win.c:\spulled\sin\slatest\schanges\sfrom\ssrc/os_unix.c;\supdated\stracing;\smisc.\simprovements.
- D 2010-05-12T17:14:59
+ -----BEGIN PGP SIGNED MESSAGE-----
+ Hash: SHA1
 -C Simplifications\sto\sthe\sSHM\simplementation\sin\sos_unix.c,\staking\sadvantage\nof\sthe\sremoval\sof\sthe\sLinuxThreads\smess.
 -D 2010-05-14T14:52:25
++C Pull\sin\sall\sthe\slatest\schanges\sfrom\sthe\strunk.\nUpdate\sthe\swin32\sSHM\smethods\sto\swork\swith\sthe\snew\sinterface\sdesign.
++D 2010-05-14T16:34:35
  F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
  F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
  F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@@ -145,17 -148,17 +148,17 @@@ F src/mutex.c e2358d8f9a9021ab0bba4d511
  F src/mutex.h 6fde601e55fa6c3fae768783c439797ab84c87c6
  F src/mutex_noop.c 10ae943d26ba86ea92319f72adbb501a89c563e0
  F src/mutex_os2.c 20477db50cf3817c2f1cd3eb61e5c177e50231db
- F src/mutex_unix.c 04a25238abce7e3d06b358dcf706e26624270809
- F src/mutex_w32.c 4cc201c1bfd11d1562810554ff5500e735559d7e
+ F src/mutex_unix.c becb8c4e07616abf84650d3687d62a1461d5d9cd
+ F src/mutex_w32.c fb1cf87c5a88b56c7df0d9ddb796ed9641046c3d
  F src/notify.c cbfa66a836da3a51567209636e6a94059c137930
- F src/os.c aec6922553585a25d5655666defc125a7e217674
- F src/os.h b389844e5469a2918e8a45fe6ae52b4c28dfb2b2
- F src/os_common.h 0d6ee583b6ee3185eb9d951f890c6dd03021a08d
- F src/os_os2.c 8ad77a418630d7dee91d1bb04f79c2096301d3a0
- F src/os_unix.c 34fe71c67fce72360411d60fe069c7f0dc612dd0
- F src/os_win.c 858e38344cab4b8c82be3263dd997c8f0f07ee0c
- F src/pager.c a47af9c2c9ca425bd68642d61764266331a3323f
- F src/pager.h 934b598583a9d936bb13c37d62a2fe68ac48781c
+ F src/os.c c0a5dfce2a214dacb679425632d04f8a2021f364
+ F src/os.h 8a7e2456237ecf3a2e55b02f9fe6091f1ad36902
+ F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
+ F src/os_os2.c 665876d5eec7585226b0a1cf5e18098de2b2da19
+ F src/os_unix.c 025da44ba18d91c2d0205e667bae4dd47be13639
 -F src/os_win.c 70c4a3327716213b59adf3a8adf2d5318b044a19
++F src/os_win.c e0a74dd60e5114ebafdd8372b0d037cb0e960176
+ F src/pager.c 1e163a82ae8405433dca559831caa06aafbba3b0
+ F src/pager.h 76466c3a5af56943537f68b1f16567101a0cd1d0
  F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
  F src/pcache.c ace8f6a5ecd4711cc66a1b23053be7109bd437cf
  F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
@@@ -813,7 -816,14 +816,14 @@@ F tool/speedtest2.tcl ee2149167303ba8e9
  F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
  F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
  F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
- P 111ad59f21d53d1ec63c084ca5f98f2aaf7cd070
- R dbc78c75ab3394a3992dedd59d6e1ec0
- U shaneh
- Z 1406477810564323a0dea454027b6d3a
 -P e294b696ba91512b1ca5547774c51ea07b4cb5bc
 -R 21f94067ad533c60202276014029d639
++P 76504726a1ef7f6a0445ec800776462138b22d72 d1debe5def82a6bc72f11b8787176ac60259630f
++R a9795407fa84d51fbed2fe19974b207a
+ U drh
 -Z 433a8524a713de9ce43e3d2748510f46
++Z d79712dbdc8aee8b22b73408f9d8d19b
+ -----BEGIN PGP SIGNATURE-----
+ Version: GnuPG v1.4.6 (GNU/Linux)
 -iD8DBQFL7WOsoxKgR168RlERAjJgAJ9zjWsl8oBYzeTvVFGM58MGDrdXDwCfV8pN
 -CnLKIoKp0Sl7DOCRB0tGSS8=
 -=V8Bz
++iD8DBQFL7XueoxKgR168RlERAmQDAJ9A6pB3LSLevi49j5UgkI8P8vCmtQCaAs3i
++afk+KXni4+86rCQ2tTbJWk8=
++=dADp
+ -----END PGP SIGNATURE-----
diff --cc manifest.uuid
index 0bf12bb0741fb084f35f550cf6a387f0751baa71,f3ccfbe4cd759cc5effe9e9bda76679cbf07ff66..eff35a07a14e951a37c724046f4b5b9a1548999e
@@@ -1,1 -1,1 +1,1 @@@
- 76504726a1ef7f6a0445ec800776462138b22d72
 -d1debe5def82a6bc72f11b8787176ac60259630f
++4b69f2cd315b6b66d10e5190d235114788853258
diff --cc src/os_win.c
index 77831152887e8e9d34ce9bf85c4b6dca658176a4,664d15ccbcbf92fe6fb0b73fcb4193f1891a83da..29898eb78b9f7acda846ca213e3a9b347687f794
  # define FormatMessageW(a,b,c,d,e,f,g) 0
  #endif
  
++/* Forward references */
++typedef struct winShm winShm;           /* A connection to shared-memory */
++typedef struct winShmNode winShmNode;   /* A region of shared-memory */
++
  /*
  ** WinCE lacks native support for file locking so we have to fake it
  ** with some code of our own.
@@@ -95,12 -95,12 +99,15 @@@ typedef struct winceLock 
  */
  typedef struct winFile winFile;
  struct winFile {
--  const sqlite3_io_methods *pMethod;/* Must be first */
++  const sqlite3_io_methods *pMethod; /*** Must be first ***/
++  sqlite3_vfs *pVfs;      /* The VFS used to open this file */
    HANDLE h;               /* Handle for accessing the file */
    unsigned char locktype; /* Type of lock currently held on this file */
    short sharedLockByte;   /* Randomly chosen byte used as a shared lock */
    DWORD lastErrno;        /* The Windows errno from the last I/O error */
    DWORD sectorSize;       /* Sector size of the device file is on */
++  winShm *pShm;           /* Instance of shared memory on this file */
++  const char *zPath;      /* Full pathname of this file */
  #if SQLITE_OS_WINCE
    WCHAR *zDeleteOnClose;  /* Name of file to delete when closing */
    HANDLE hMutex;          /* Mutex used to control access to shared lock */  
@@@ -629,6 -629,7 +636,8 @@@ static int winClose(sqlite3_file *id)
    winFile *pFile = (winFile*)id;
  
    assert( id!=0 );
++  assert( pFile->pShm==0 );
+   OSTRACE(("CLOSE %d\n", pFile->h));
    do{
      rc = CloseHandle(pFile->h);
    }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (Sleep(100), 1) );
@@@ -746,24 -746,24 +755,25 @@@ static int winWrite
  static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
    LONG upperBits = (LONG)((nByte>>32) & 0x7fffffff);
    LONG lowerBits = (LONG)(nByte & 0xffffffff);
 -  DWORD rc;
 +  DWORD dwRet;
    winFile *pFile = (winFile*)id;
    DWORD error;
 +  int rc = SQLITE_OK;
  
    assert( id!=0 );
+   OSTRACE(("TRUNCATE %d %lld\n", pFile->h, nByte));
    SimulateIOError(return SQLITE_IOERR_TRUNCATE);
 -  rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
 -  if( rc==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
 +  dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
 +  if( dwRet==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
      pFile->lastErrno = error;
 -    return SQLITE_IOERR_TRUNCATE;
 -  }
 +    rc = SQLITE_IOERR_TRUNCATE;
    /* SetEndOfFile will fail if nByte is negative */
 -  if( !SetEndOfFile(pFile->h) ){
 +  }else if( !SetEndOfFile(pFile->h) ){
      pFile->lastErrno = GetLastError();
 -    return SQLITE_IOERR_TRUNCATE;
 +    rc = SQLITE_IOERR_TRUNCATE;
    }
 -  return SQLITE_OK;
 +  OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc==SQLITE_OK ? "ok" : "failed"));
 +  return rc;
  }
  
  #ifdef SQLITE_TEST
@@@ -1139,1170 -1139,372 +1149,1325 @@@ static int winDeviceCharacteristics(sql
    return 0;
  }
  
- /*
- ** This vector defines all the methods that can operate on an
- ** sqlite3_file for win32.
++/****************************************************************************
++********************************* Shared Memory *****************************
++**
++** The next subdivision of code manages the shared-memory primitives.
 +*/
- static const sqlite3_io_methods winIoMethod = {
-   1,                        /* iVersion */
-   winClose,
-   winRead,
-   winWrite,
-   winTruncate,
-   winSync,
-   winFileSize,
-   winLock,
-   winUnlock,
-   winCheckReservedLock,
-   winFileControl,
-   winSectorSize,
-   winDeviceCharacteristics
- };
++#ifndef SQLITE_OMIT_WAL
 +
- /***************************************************************************
- ** Here ends the I/O methods that form the sqlite3_io_methods object.
++/*
++** Helper functions to obtain and relinquish the global mutex. The
++** global mutex is used to protect the winLockInfo objects used by 
++** this file, all of which may be shared by multiple threads.
 +**
- ** The next block of code implements the VFS methods.
- ****************************************************************************/
++** Function winShmMutexHeld() is used to assert() that the global mutex 
++** is held when required. This function is only used as part of assert() 
++** statements. e.g.
++**
++**   winShmEnterMutex()
++**     assert( winShmMutexHeld() );
++**   winEnterLeave()
++*/
++static void winShmEnterMutex(void){
++  sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++}
++static void winShmLeaveMutex(void){
++  sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++}
++#ifdef SQLITE_DEBUG
++static int winShmMutexHeld(void) {
++  return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++}
++#endif
 +
 +/*
- ** Convert a UTF-8 filename into whatever form the underlying
- ** operating system wants filenames in.  Space to hold the result
- ** is obtained from malloc and must be freed by the calling
- ** function.
- */
- static void *convertUtf8Filename(const char *zFilename){
-   void *zConverted = 0;
-   if( isNT() ){
-     zConverted = utf8ToUnicode(zFilename);
- /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
++** Object used to represent a single file opened and mmapped to provide
++** shared memory.  When multiple threads all reference the same
++** log-summary, each thread has its own winFile object, but they all
++** point to a single instance of this object.  In other words, each
++** log-summary is opened only once per process.
++**
++** winShmMutexHeld() must be true when creating or destroying
++** this object or while reading or writing the following fields:
++**
++**      nRef
++**      pNext 
++**
++** The following fields are read-only after the object is created:
++** 
++**      fid
++**      zFilename
++**
++** Either winShmNode.mutex must be held or winShmNode.nRef==0 and
++** winShmMutexHeld() is true when reading or writing any other field
++** in this structure.
++**
++** To avoid deadlocks, mutex and mutexBuf are always released in the
++** reverse order that they are acquired.  mutexBuf is always acquired
++** first and released last.  This invariant is check by asserting
++** sqlite3_mutex_notheld() on mutex whenever mutexBuf is acquired or
++** released.
 +*/
- #if SQLITE_OS_WINCE==0
-   }else{
-     zConverted = utf8ToMbcs(zFilename);
++struct winShmNode {
++  sqlite3_mutex *mutex;      /* Mutex to access this object */
++  sqlite3_mutex *mutexBuf;   /* Mutex to access zBuf[] */
++  char *zFilename;           /* Name of the file */
++  winFile hFile;             /* File handle from winOpen */
++  HANDLE hMap;               /* File handle from CreateFileMapping */
++  DWORD lastErrno;           /* The Windows errno from the last I/O error */
++  int szMap;                 /* Size of the mapping of file into memory */
++  char *pMMapBuf;            /* Where currently mmapped().  NULL if unmapped */
++  int nRef;                  /* Number of winShm objects pointing to this */
++  winShm *pFirst;            /* All winShm objects pointing to this */
++  winShmNode *pNext;         /* Next in list of all winShmNode objects */
++#ifdef SQLITE_DEBUG
++  u8 exclMask;               /* Mask of exclusive locks held */
++  u8 sharedMask;             /* Mask of shared locks held */
++  u8 nextShmId;              /* Next available winShm.id value */
 +#endif
-   }
-   /* caller will handle out of memory */
-   return zConverted;
- }
++};
 +
 +/*
- ** Create a temporary file name in zBuf.  zBuf must be big enough to
- ** hold at pVfs->mxPathname characters.
++** A global array of all winShmNode objects.
++**
++** The winShmMutexHeld() must be true while reading or writing this list.
 +*/
- static int getTempname(int nBuf, char *zBuf){
-   static char zChars[] =
-     "abcdefghijklmnopqrstuvwxyz"
-     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-     "0123456789";
-   size_t i, j;
-   char zTempPath[MAX_PATH+1];
-   if( sqlite3_temp_directory ){
-     sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory);
-   }else if( isNT() ){
-     char *zMulti;
-     WCHAR zWidePath[MAX_PATH];
-     GetTempPathW(MAX_PATH-30, zWidePath);
-     zMulti = unicodeToUtf8(zWidePath);
-     if( zMulti ){
-       sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti);
-       free(zMulti);
-     }else{
-       return SQLITE_NOMEM;
-     }
- /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
- ** Since the ASCII version of these Windows API do not exist for WINCE,
- ** it's important to not reference them for WINCE builds.
++static winShmNode *winShmNodeList = 0;
++
++/*
++** Structure used internally by this VFS to record the state of an
++** open shared memory connection.
++**
++** winShm.pFile->mutex must be held while reading or writing the
++** winShm.pNext and winShm.locks[] elements.
++**
++** The winShm.pFile element is initialized when the object is created
++** and is read-only thereafter.
 +*/
- #if SQLITE_OS_WINCE==0
-   }else{
-     char *zUtf8;
-     char zMbcsPath[MAX_PATH];
-     GetTempPathA(MAX_PATH-30, zMbcsPath);
-     zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath);
-     if( zUtf8 ){
-       sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8);
-       free(zUtf8);
-     }else{
-       return SQLITE_NOMEM;
-     }
++struct winShm {
++  winShmNode *pShmNode;      /* The underlying winShmNode object */
++  winShm *pNext;             /* Next winShm with the same winShmNode */
++  u8 lockState;              /* Current lock state */
++  u8 hasMutex;               /* True if holding the winShmNode mutex */
++  u8 hasMutexBuf;            /* True if holding pFile->mutexBuf */
++  u8 sharedMask;             /* Mask of shared locks held */
++  u8 exclMask;               /* Mask of exclusive locks held */
++#ifdef SQLITE_DEBUG
++  u8 id;                     /* Id of this connection with its winShmNode */
 +#endif
-   }
-   for(i=sqlite3Strlen30(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
-   zTempPath[i] = 0;
-   sqlite3_snprintf(nBuf-30, zBuf,
-                    "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath);
-   j = sqlite3Strlen30(zBuf);
-   sqlite3_randomness(20, &zBuf[j]);
-   for(i=0; i<20; i++, j++){
-     zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
-   }
-   zBuf[j] = 0;
-   OSTRACE2("TEMP FILENAME: %s\n", zBuf);
-   return SQLITE_OK; 
- }
++};
 +
 +/*
- ** The return value of getLastErrorMsg
- ** is zero if the error message fits in the buffer, or non-zero
- ** otherwise (if the message was truncated).
++** Size increment by which shared memory grows
 +*/
- static int getLastErrorMsg(int nBuf, char *zBuf){
-   /* FormatMessage returns 0 on failure.  Otherwise it
-   ** returns the number of TCHARs written to the output
-   ** buffer, excluding the terminating null char.
-   */
-   DWORD error = GetLastError();
-   DWORD dwLen = 0;
-   char *zOut = 0;
++#define SQLITE_WIN_SHM_INCR  4096
 +
-   if( isNT() ){
-     WCHAR *zTempWide = NULL;
-     dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
-                            NULL,
-                            error,
-                            0,
-                            (LPWSTR) &zTempWide,
-                            0,
-                            0);
-     if( dwLen > 0 ){
-       /* allocate a buffer and convert to UTF8 */
-       zOut = unicodeToUtf8(zTempWide);
-       /* free the system buffer allocated by FormatMessage */
-       LocalFree(zTempWide);
-     }
- /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
- ** Since the ASCII version of these Windows API do not exist for WINCE,
- ** it's important to not reference them for WINCE builds.
++/*
++** Constants used for locking
 +*/
- #if SQLITE_OS_WINCE==0
-   }else{
-     char *zTemp = NULL;
-     dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
-                            NULL,
-                            error,
-                            0,
-                            (LPSTR) &zTemp,
-                            0,
-                            0);
-     if( dwLen > 0 ){
-       /* allocate a buffer and convert to UTF8 */
-       zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
-       /* free the system buffer allocated by FormatMessage */
-       LocalFree(zTemp);
-     }
- #endif
-   }
-   if( 0 == dwLen ){
-     sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error);
-   }else{
-     /* copy a maximum of nBuf chars to output buffer */
-     sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
-     /* free the UTF8 buffer */
-     free(zOut);
-   }
-   return 0;
- }
++#define WIN_SHM_BASE      32        /* Byte offset of the first lock byte */
++#define WIN_SHM_DMS       0x01      /* Mask for Dead-Man-Switch lock */
++#define WIN_SHM_A         0x10      /* Mask for region locks... */
++#define WIN_SHM_B         0x20
++#define WIN_SHM_C         0x40
++#define WIN_SHM_D         0x80
 +
++#ifdef SQLITE_DEBUG
 +/*
- ** Open a file.
++** Return a pointer to a nul-terminated string in static memory that
++** describes a locking mask.  The string is of the form "MSABCD" with
++** each character representing a lock.  "M" for MUTEX, "S" for DMS, 
++** and "A" through "D" for the region locks.  If a lock is held, the
++** letter is shown.  If the lock is not held, the letter is converted
++** to ".".
++**
++** This routine is for debugging purposes only and does not appear
++** in a production build.
 +*/
- static int winOpen(
-   sqlite3_vfs *pVfs,        /* Not used */
-   const char *zName,        /* Name of the file (UTF-8) */
-   sqlite3_file *id,         /* Write the SQLite file handle here */
-   int flags,                /* Open mode flags */
-   int *pOutFlags            /* Status return flags */
- ){
-   HANDLE h;
-   DWORD dwDesiredAccess;
-   DWORD dwShareMode;
-   DWORD dwCreationDisposition;
-   DWORD dwFlagsAndAttributes = 0;
- #if SQLITE_OS_WINCE
-   int isTemp = 0;
- #endif
-   winFile *pFile = (winFile*)id;
-   void *zConverted;                 /* Filename in OS encoding */
-   const char *zUtf8Name = zName;    /* Filename in UTF-8 encoding */
-   char zTmpname[MAX_PATH+1];        /* Buffer used to create temp filename */
-   assert( id!=0 );
-   UNUSED_PARAMETER(pVfs);
-   pFile->h = INVALID_HANDLE_VALUE;
-   /* If the second argument to this function is NULL, generate a 
-   ** temporary file name to use 
-   */
-   if( !zUtf8Name ){
-     int rc = getTempname(MAX_PATH+1, zTmpname);
-     if( rc!=SQLITE_OK ){
-       return rc;
-     }
-     zUtf8Name = zTmpname;
-   }
++static const char *winShmLockString(u8 mask){
++  static char zBuf[48];
++  static int iBuf = 0;
++  char *z;
 +
-   /* Convert the filename to the system encoding. */
-   zConverted = convertUtf8Filename(zUtf8Name);
-   if( zConverted==0 ){
-     return SQLITE_NOMEM;
-   }
++  z = &zBuf[iBuf];
++  iBuf += 8;
++  if( iBuf>=sizeof(zBuf) ) iBuf = 0;
 +
-   if( flags & SQLITE_OPEN_READWRITE ){
-     dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
-   }else{
-     dwDesiredAccess = GENERIC_READ;
-   }
-   /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is 
-   ** created. SQLite doesn't use it to indicate "exclusive access" 
-   ** as it is usually understood.
-   */
-   assert(!(flags & SQLITE_OPEN_EXCLUSIVE) || (flags & SQLITE_OPEN_CREATE));
-   if( flags & SQLITE_OPEN_EXCLUSIVE ){
-     /* Creates a new file, only if it does not already exist. */
-     /* If the file exists, it fails. */
-     dwCreationDisposition = CREATE_NEW;
-   }else if( flags & SQLITE_OPEN_CREATE ){
-     /* Open existing file, or create if it doesn't exist */
-     dwCreationDisposition = OPEN_ALWAYS;
-   }else{
-     /* Opens a file, only if it exists. */
-     dwCreationDisposition = OPEN_EXISTING;
-   }
-   dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
-   if( flags & SQLITE_OPEN_DELETEONCLOSE ){
- #if SQLITE_OS_WINCE
-     dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN;
-     isTemp = 1;
- #else
-     dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY
-                                | FILE_ATTRIBUTE_HIDDEN
-                                | FILE_FLAG_DELETE_ON_CLOSE;
- #endif
-   }else{
-     dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
-   }
-   /* Reports from the internet are that performance is always
-   ** better if FILE_FLAG_RANDOM_ACCESS is used.  Ticket #2699. */
- #if SQLITE_OS_WINCE
-   dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
- #endif
-   if( isNT() ){
-     h = CreateFileW((WCHAR*)zConverted,
-        dwDesiredAccess,
-        dwShareMode,
-        NULL,
-        dwCreationDisposition,
-        dwFlagsAndAttributes,
-        NULL
-     );
- /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
- ** Since the ASCII version of these Windows API do not exist for WINCE,
- ** it's important to not reference them for WINCE builds.
- */
- #if SQLITE_OS_WINCE==0
-   }else{
-     h = CreateFileA((char*)zConverted,
-        dwDesiredAccess,
-        dwShareMode,
-        NULL,
-        dwCreationDisposition,
-        dwFlagsAndAttributes,
-        NULL
-     );
- #endif
-   }
-   OSTRACE(("OPEN %d %s 0x%lx %s\n", 
-            h, zName, dwDesiredAccess, 
-            h==INVALID_HANDLE_VALUE ? "failed" : "ok"));
-   if( h==INVALID_HANDLE_VALUE ){
-     free(zConverted);
-     if( flags & SQLITE_OPEN_READWRITE ){
-       return winOpen(pVfs, zName, id, 
-              ((flags|SQLITE_OPEN_READONLY)&~SQLITE_OPEN_READWRITE), pOutFlags);
-     }else{
-       return SQLITE_CANTOPEN_BKPT;
-     }
-   }
-   if( pOutFlags ){
-     if( flags & SQLITE_OPEN_READWRITE ){
-       *pOutFlags = SQLITE_OPEN_READWRITE;
-     }else{
-       *pOutFlags = SQLITE_OPEN_READONLY;
-     }
-   }
-   memset(pFile, 0, sizeof(*pFile));
-   pFile->pMethod = &winIoMethod;
-   pFile->h = h;
-   pFile->lastErrno = NO_ERROR;
-   pFile->sectorSize = getSectorSize(pVfs, zUtf8Name);
- #if SQLITE_OS_WINCE
-   if( (flags & (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)) ==
-                (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)
-        && !winceCreateLock(zName, pFile)
-   ){
-     CloseHandle(h);
-     free(zConverted);
-     return SQLITE_CANTOPEN_BKPT;
-   }
-   if( isTemp ){
-     pFile->zDeleteOnClose = zConverted;
-   }else
- #endif
-   {
-     free(zConverted);
-   }
-   OpenCounter(+1);
-   return SQLITE_OK;
++  z[0] = (mask & WIN_SHM_DMS)   ? 'S' : '.';
++  z[1] = (mask & WIN_SHM_A)     ? 'A' : '.';
++  z[2] = (mask & WIN_SHM_B)     ? 'B' : '.';
++  z[3] = (mask & WIN_SHM_C)     ? 'C' : '.';
++  z[4] = (mask & WIN_SHM_D)     ? 'D' : '.';
++  z[5] = 0;
++  return z;
 +}
++#endif /* SQLITE_DEBUG */
 +
 +/*
- ** Delete the named file.
++** Apply posix advisory locks for all bytes identified in lockMask.
 +**
- ** Note that windows does not allow a file to be deleted if some other
- ** process has it open.  Sometimes a virus scanner or indexing program
- ** will open a journal file shortly after it is created in order to do
- ** whatever it does.  While this other process is holding the
- ** file open, we will be unable to delete it.  To work around this
- ** problem, we delay 100 milliseconds and try to delete again.  Up
- ** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
- ** up and returning an error.
++** lockMask might contain multiple bits but all bits are guaranteed
++** to be contiguous.
++**
++** Locks block if the mask is exactly WIN_SHM_C and are non-blocking
++** otherwise.
 +*/
- #define MX_DELETION_ATTEMPTS 5
- static int winDelete(
-   sqlite3_vfs *pVfs,          /* Not used on win32 */
-   const char *zFilename,      /* Name of file to delete */
-   int syncDir                 /* Not used on win32 */
++#define _SHM_UNLCK  1
++#define _SHM_RDLCK  2
++#define _SHM_WRLCK  3
++static int winShmSystemLock(
++  winShmNode *pFile,    /* Apply locks to this open shared-memory segment */
++  int lockType,         /* _SHM_UNLCK, _SHM_RDLCK, or _SHM_WRLCK */
++  u8 lockMask           /* Which bytes to lock or unlock */
 +){
-   int cnt = 0;
-   DWORD rc;
-   DWORD error = 0;
-   void *zConverted = convertUtf8Filename(zFilename);
-   UNUSED_PARAMETER(pVfs);
-   UNUSED_PARAMETER(syncDir);
-   if( zConverted==0 ){
-     return SQLITE_NOMEM;
-   }
-   SimulateIOError(return SQLITE_IOERR_DELETE);
-   if( isNT() ){
-     do{
-       DeleteFileW(zConverted);
-     }while(   (   ((rc = GetFileAttributesW(zConverted)) != INVALID_FILE_ATTRIBUTES)
-                || ((error = GetLastError()) == ERROR_ACCESS_DENIED))
-            && (++cnt < MX_DELETION_ATTEMPTS)
-            && (Sleep(100), 1) );
- /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
- ** Since the ASCII version of these Windows API do not exist for WINCE,
- ** it's important to not reference them for WINCE builds.
- */
- #if SQLITE_OS_WINCE==0
-   }else{
-     do{
-       DeleteFileA(zConverted);
-     }while(   (   ((rc = GetFileAttributesA(zConverted)) != INVALID_FILE_ATTRIBUTES)
-                || ((error = GetLastError()) == ERROR_ACCESS_DENIED))
-            && (++cnt < MX_DELETION_ATTEMPTS)
-            && (Sleep(100), 1) );
- #endif
-   }
-   free(zConverted);
-   OSTRACE(("DELETE \"%s\" %s\n", zFilename, (   (rc == INVALID_FILE_ATTRIBUTES) 
-                                              && (error == ERROR_FILE_NOT_FOUND)) ? "ok" : "failed" ));
-   return (   (rc == INVALID_FILE_ATTRIBUTES) 
-           && (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK : SQLITE_IOERR_DELETE;
- }
++  OVERLAPPED ovlp;
++  DWORD dwFlags;
++  int nBytes;           /* Number of bytes to lock */
++  int i;                /* Offset into the locking byte range */
++  int rc = 0;           /* Result code form Lock/UnlockFileEx() */
++  u8 mask;              /* Mask of bits in lockMask */
 +
- /*
- ** Check the existance and status of a file.
- */
- static int winAccess(
-   sqlite3_vfs *pVfs,         /* Not used on win32 */
-   const char *zFilename,     /* Name of file to check */
-   int flags,                 /* Type of test to make on this file */
-   int *pResOut               /* OUT: Result */
- ){
-   DWORD attr;
-   int rc = 0;
-   void *zConverted = convertUtf8Filename(zFilename);
-   UNUSED_PARAMETER(pVfs);
-   if( zConverted==0 ){
-     return SQLITE_NOMEM;
-   }
-   if( isNT() ){
-     attr = GetFileAttributesW((WCHAR*)zConverted);
- /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
- ** Since the ASCII version of these Windows API do not exist for WINCE,
- ** it's important to not reference them for WINCE builds.
- */
- #if SQLITE_OS_WINCE==0
++  /* Access to the winShmNode object is serialized by the caller */
++  assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
++
++  /* Initialize the locking parameters */
++  if( lockMask==WIN_SHM_C && lockType!=_SHM_UNLCK ){
++    dwFlags = 0;
++    OSTRACE(("SHM-LOCK %d requesting blocking lock %s\n", 
++             pFile->hFile.h,
++             winShmLockString(lockMask)));
 +  }else{
-     attr = GetFileAttributesA((char*)zConverted);
- #endif
-   }
-   free(zConverted);
-   switch( flags ){
-     case SQLITE_ACCESS_READ:
-     case SQLITE_ACCESS_EXISTS:
-       rc = attr!=INVALID_FILE_ATTRIBUTES;
-       break;
-     case SQLITE_ACCESS_READWRITE:
-       rc = (attr & FILE_ATTRIBUTE_READONLY)==0;
-       break;
-     default:
-       assert(!"Invalid flags argument");
++    dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
++    OSTRACE(("SHM-LOCK %d requesting %s %s\n", 
++             pFile->hFile.h,
++             lockType!=_SHM_UNLCK ? "lock" : "unlock", 
++             winShmLockString(lockMask)));
 +  }
-   *pResOut = rc;
-   return SQLITE_OK;
- }
++  if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
 +
++  /* Find the first bit in lockMask that is set */
++  for(i=0, mask=0x01; mask!=0 && (lockMask&mask)==0; mask <<= 1, i++){}
++  assert( mask!=0 );
++  memset(&ovlp, 0, sizeof(OVERLAPPED));
++  ovlp.Offset = i+WIN_SHM_BASE;
++  nBytes = 1;
 +
- /*
- ** Turn a relative pathname into a full pathname.  Write the full
- ** pathname into zOut[].  zOut[] will be at least pVfs->mxPathname
- ** bytes in size.
- */
- static int winFullPathname(
-   sqlite3_vfs *pVfs,            /* Pointer to vfs object */
-   const char *zRelative,        /* Possibly relative input path */
-   int nFull,                    /* Size of output buffer in bytes */
-   char *zFull                   /* Output buffer */
- ){
-   
- #if defined(__CYGWIN__)
-   UNUSED_PARAMETER(nFull);
-   cygwin_conv_to_full_win32_path(zRelative, zFull);
-   return SQLITE_OK;
- #endif
++  /* Extend the locking range for each additional bit that is set */
++  mask <<= 1;
++  while( mask!=0 && (lockMask & mask)!=0 ){
++    nBytes++;
++    mask <<= 1;
++  }
 +
- #if SQLITE_OS_WINCE
-   UNUSED_PARAMETER(nFull);
-   /* WinCE has no concept of a relative pathname, or so I am told. */
-   sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zRelative);
-   return SQLITE_OK;
- #endif
++  /* Verify that all bits set in lockMask are contiguous */
++  assert( mask==0 || (lockMask & ~(mask | (mask-1)))==0 );
 +
- #if !SQLITE_OS_WINCE && !defined(__CYGWIN__)
-   int nByte;
-   void *zConverted;
-   char *zOut;
-   UNUSED_PARAMETER(nFull);
-   zConverted = convertUtf8Filename(zRelative);
-   if( isNT() ){
-     WCHAR *zTemp;
-     nByte = GetFullPathNameW((WCHAR*)zConverted, 0, 0, 0) + 3;
-     zTemp = malloc( nByte*sizeof(zTemp[0]) );
-     if( zTemp==0 ){
-       free(zConverted);
-       return SQLITE_NOMEM;
-     }
-     GetFullPathNameW((WCHAR*)zConverted, nByte, zTemp, 0);
-     free(zConverted);
-     zOut = unicodeToUtf8(zTemp);
-     free(zTemp);
- /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
- ** Since the ASCII version of these Windows API do not exist for WINCE,
- ** it's important to not reference them for WINCE builds.
- */
- #if SQLITE_OS_WINCE==0
++  /* Release/Acquire the system-level lock */
++  if( lockType==_SHM_UNLCK ){
++    for(i=0; i<nBytes; i++, ovlp.Offset++){
++      rc = UnlockFileEx(pFile->hFile.h, 0, 1, 0, &ovlp);
++      if( !rc ) break;
++    }
 +  }else{
-     char *zTemp;
-     nByte = GetFullPathNameA((char*)zConverted, 0, 0, 0) + 3;
-     zTemp = malloc( nByte*sizeof(zTemp[0]) );
-     if( zTemp==0 ){
-       free(zConverted);
-       return SQLITE_NOMEM;
++    /* release old individual byte locks (if any)
++    ** and set new individual byte locks */
++    for(i=0; i<nBytes; i++, ovlp.Offset++){
++      UnlockFileEx(pFile->hFile.h, 0, 1, 0, &ovlp);
++      rc = LockFileEx(pFile->hFile.h, dwFlags, 0, 1, 0, &ovlp);
++      if( !rc ) break;
 +    }
-     GetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
-     free(zConverted);
-     zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
-     free(zTemp);
- #endif
 +  }
-   if( zOut ){
-     sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zOut);
-     free(zOut);
-     return SQLITE_OK;
++  if( !rc ){
++    OSTRACE(("SHM-LOCK %d %s ERROR 0x%08lx\n", 
++             pFile->hFile.h,
++             lockType==_SHM_UNLCK ? "UnlockFileEx" : "LockFileEx",
++             GetLastError()));
++    /* release individual byte locks (if any) */
++    ovlp.Offset-=i;
++    for(i=0; i<nBytes; i++, ovlp.Offset++){
++      UnlockFileEx(pFile->hFile.h, 0, 1, 0, &ovlp);
++    }
++  }
++  rc = (rc!=0) ? SQLITE_OK : SQLITE_BUSY;
++
++  /* Update the global lock state and do debug tracing */
++#ifdef SQLITE_DEBUG
++  OSTRACE(("SHM-LOCK %d ", pFile->hFile.h));
++  if( rc==SQLITE_OK ){
++    if( lockType==_SHM_UNLCK ){
++      OSTRACE(("unlock ok"));
++      pFile->exclMask &= ~lockMask;
++      pFile->sharedMask &= ~lockMask;
++    }else if( lockType==_SHM_RDLCK ){
++      OSTRACE(("read-lock ok"));
++      pFile->exclMask &= ~lockMask;
++      pFile->sharedMask |= lockMask;
++    }else{
++      assert( lockType==_SHM_WRLCK );
++      OSTRACE(("write-lock ok"));
++      pFile->exclMask |= lockMask;
++      pFile->sharedMask &= ~lockMask;
++    }
 +  }else{
-     return SQLITE_NOMEM;
++    if( lockType==_SHM_UNLCK ){
++      OSTRACE(("unlock failed"));
++    }else if( lockType==_SHM_RDLCK ){
++      OSTRACE(("read-lock failed"));
++    }else{
++      assert( lockType==_SHM_WRLCK );
++      OSTRACE(("write-lock failed"));
++    }
 +  }
++  OSTRACE((" - change requested %s - afterwards %s:%s\n",
++           winShmLockString(lockMask),
++           winShmLockString(pFile->sharedMask),
++           winShmLockString(pFile->exclMask)));
 +#endif
++
++  return rc;
 +}
 +
 +/*
- ** Get the sector size of the device used to store
- ** file.
++** For connection p, unlock all of the locks identified by the unlockMask
++** parameter.
 +*/
- static int getSectorSize(
-     sqlite3_vfs *pVfs,
-     const char *zRelative     /* UTF-8 file name */
++static int winShmUnlock(
++  winShmNode *pFile,   /* The underlying shared-memory file */
++  winShm *p,           /* The connection to be unlocked */
++  u8 unlockMask         /* Mask of locks to be unlocked */
 +){
-   DWORD bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE;
-   /* GetDiskFreeSpace is not supported under WINCE */
- #if SQLITE_OS_WINCE
-   UNUSED_PARAMETER(pVfs);
-   UNUSED_PARAMETER(zRelative);
- #else
-   char zFullpath[MAX_PATH+1];
-   int rc;
-   DWORD dwRet = 0;
-   DWORD dwDummy;
++  int rc;      /* Result code */
++  winShm *pX; /* For looping over all sibling connections */
++  u8 allMask;  /* Union of locks held by connections other than "p" */
 +
-   /*
-   ** We need to get the full path name of the file
-   ** to get the drive letter to look up the sector
-   ** size.
-   */
-   rc = winFullPathname(pVfs, zRelative, MAX_PATH, zFullpath);
-   if( rc == SQLITE_OK )
-   {
-     void *zConverted = convertUtf8Filename(zFullpath);
-     if( zConverted ){
-       if( isNT() ){
-         /* trim path to just drive reference */
-         WCHAR *p = zConverted;
-         for(;*p;p++){
-           if( *p == '\\' ){
-             *p = '\0';
-             break;
-           }
-         }
-         dwRet = GetDiskFreeSpaceW((WCHAR*)zConverted,
-                                   &dwDummy,
-                                   &bytesPerSector,
-                                   &dwDummy,
-                                   &dwDummy);
-       }else{
-         /* trim path to just drive reference */
-         char *p = (char *)zConverted;
-         for(;*p;p++){
-           if( *p == '\\' ){
-             *p = '\0';
-             break;
-           }
-         }
-         dwRet = GetDiskFreeSpaceA((char*)zConverted,
-                                   &dwDummy,
-                                   &bytesPerSector,
-                                   &dwDummy,
-                                   &dwDummy);
-       }
-       free(zConverted);
-     }
-     if( !dwRet ){
-       bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE;
-     }
++  /* Access to the winShmNode object is serialized by the caller */
++  assert( sqlite3_mutex_held(pFile->mutex) );
++
++  /* don't attempt to unlock anything we don't have locks for */
++  if( (unlockMask & (p->exclMask|p->sharedMask)) != unlockMask ){
++    OSTRACE(("SHM-LOCK %d unlocking more than we have locked - requested %s - have %s\n",
++             pFile->hFile.h,
++             winShmLockString(unlockMask),
++             winShmLockString(p->exclMask|p->sharedMask)));
++    unlockMask &= (p->exclMask|p->sharedMask);
 +  }
- #endif
-   return (int) bytesPerSector; 
- }
 +
- #ifndef SQLITE_OMIT_LOAD_EXTENSION
- /*
- ** Interfaces for opening a shared library, finding entry points
- ** within the shared library, and closing the shared library.
- */
- /*
- ** Interfaces for opening a shared library, finding entry points
- ** within the shared library, and closing the shared library.
- */
- static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
-   HANDLE h;
-   void *zConverted = convertUtf8Filename(zFilename);
-   UNUSED_PARAMETER(pVfs);
-   if( zConverted==0 ){
-     return 0;
++  /* Compute locks held by sibling connections */
++  allMask = 0;
++  for(pX=pFile->pFirst; pX; pX=pX->pNext){
++    if( pX==p ) continue;
++    assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
++    allMask |= pX->sharedMask;
 +  }
-   if( isNT() ){
-     h = LoadLibraryW((WCHAR*)zConverted);
- /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
- ** Since the ASCII version of these Windows API do not exist for WINCE,
- ** it's important to not reference them for WINCE builds.
- */
- #if SQLITE_OS_WINCE==0
++
++  /* Unlock the system-level locks */
++  if( (unlockMask & allMask)!=unlockMask ){
++    rc = winShmSystemLock(pFile, _SHM_UNLCK, unlockMask & ~allMask);
 +  }else{
-     h = LoadLibraryA((char*)zConverted);
- #endif
++    rc = SQLITE_OK;
 +  }
-   free(zConverted);
-   return (void*)h;
- }
- static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
-   UNUSED_PARAMETER(pVfs);
-   getLastErrorMsg(nBuf, zBufOut);
- }
- void (*winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
-   UNUSED_PARAMETER(pVfs);
- #if SQLITE_OS_WINCE
-   /* The GetProcAddressA() routine is only available on wince. */
-   return (void(*)(void))GetProcAddressA((HANDLE)pHandle, zSymbol);
- #else
-   /* All other windows platforms expect GetProcAddress() to take
-   ** an Ansi string regardless of the _UNICODE setting */
-   return (void(*)(void))GetProcAddress((HANDLE)pHandle, zSymbol);
- #endif
- }
- void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
-   UNUSED_PARAMETER(pVfs);
-   FreeLibrary((HANDLE)pHandle);
- }
- #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
-   #define winDlOpen  0
-   #define winDlError 0
-   #define winDlSym   0
-   #define winDlClose 0
- #endif
 +
++  /* Undo the local locks */
++  if( rc==SQLITE_OK ){
++    p->exclMask &= ~unlockMask;
++    p->sharedMask &= ~unlockMask;
++  } 
++  return rc;
++}
 +
 +/*
- ** Write up to nBuf bytes of randomness into zBuf.
++** Get reader locks for connection p on all locks in the readMask parameter.
 +*/
- static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
-   int n = 0;
-   UNUSED_PARAMETER(pVfs);
- #if defined(SQLITE_TEST)
-   n = nBuf;
-   memset(zBuf, 0, nBuf);
- #else
-   if( sizeof(SYSTEMTIME)<=nBuf-n ){
-     SYSTEMTIME x;
-     GetSystemTime(&x);
-     memcpy(&zBuf[n], &x, sizeof(x));
-     n += sizeof(x);
-   }
-   if( sizeof(DWORD)<=nBuf-n ){
-     DWORD pid = GetCurrentProcessId();
-     memcpy(&zBuf[n], &pid, sizeof(pid));
-     n += sizeof(pid);
++static int winShmSharedLock(
++  winShmNode *pFile,   /* The underlying shared-memory file */
++  winShm *p,           /* The connection to get the shared locks */
++  u8 readMask           /* Mask of shared locks to be acquired */
++){
++  int rc;        /* Result code */
++  winShm *pX;   /* For looping over all sibling connections */
++  u8 allShared;  /* Union of locks held by connections other than "p" */
++
++  /* Access to the winShmNode object is serialized by the caller */
++  assert( sqlite3_mutex_held(pFile->mutex) );
++
++  /* Find out which shared locks are already held by sibling connections.
++  ** If any sibling already holds an exclusive lock, go ahead and return
++  ** SQLITE_BUSY.
++  */
++  allShared = 0;
++  for(pX=pFile->pFirst; pX; pX=pX->pNext){
++    if( pX==p ) continue;
++    if( (pX->exclMask & readMask)!=0 ) return SQLITE_BUSY;
++    allShared |= pX->sharedMask;
 +  }
-   if( sizeof(DWORD)<=nBuf-n ){
-     DWORD cnt = GetTickCount();
-     memcpy(&zBuf[n], &cnt, sizeof(cnt));
-     n += sizeof(cnt);
++
++  /* Get shared locks at the system level, if necessary */
++  if( (~allShared) & readMask ){
++    rc = winShmSystemLock(pFile, _SHM_RDLCK, readMask);
++  }else{
++    rc = SQLITE_OK;
 +  }
-   if( sizeof(LARGE_INTEGER)<=nBuf-n ){
-     LARGE_INTEGER i;
-     QueryPerformanceCounter(&i);
-     memcpy(&zBuf[n], &i, sizeof(i));
-     n += sizeof(i);
++
++  /* Get the local shared locks */
++  if( rc==SQLITE_OK ){
++    p->sharedMask |= readMask;
 +  }
- #endif
-   return n;
++  return rc;
 +}
 +
 +/*
- ** Sleep for a little while.  Return the amount of time slept.
++** For connection p, get an exclusive lock on all locks identified in
++** the writeMask parameter.
 +*/
- static int winSleep(sqlite3_vfs *pVfs, int microsec){
-   Sleep((microsec+999)/1000);
-   UNUSED_PARAMETER(pVfs);
-   return ((microsec+999)/1000)*1000;
++static int winShmExclusiveLock(
++  winShmNode *pFile,    /* The underlying shared-memory file */
++  winShm *p,            /* The connection to get the exclusive locks */
++  u8 writeMask           /* Mask of exclusive locks to be acquired */
++){
++  int rc;        /* Result code */
++  winShm *pX;   /* For looping over all sibling connections */
++
++  /* Access to the winShmNode object is serialized by the caller */
++  assert( sqlite3_mutex_held(pFile->mutex) );
++
++  /* Make sure no sibling connections hold locks that will block this
++  ** lock.  If any do, return SQLITE_BUSY right away.
++  */
++  for(pX=pFile->pFirst; pX; pX=pX->pNext){
++    if( pX==p ) continue;
++    if( (pX->exclMask & writeMask)!=0 ) return SQLITE_BUSY;
++    if( (pX->sharedMask & writeMask)!=0 ) return SQLITE_BUSY;
++  }
++
++  /* Get the exclusive locks at the system level.  Then if successful
++  ** also mark the local connection as being locked.
++  */
++  rc = winShmSystemLock(pFile, _SHM_WRLCK, writeMask);
++  if( rc==SQLITE_OK ){
++    p->sharedMask &= ~writeMask;
++    p->exclMask |= writeMask;
++  }
++  return rc;
 +}
 +
 +/*
- ** The following variable, if set to a non-zero value, is interpreted as
- ** the number of seconds since 1970 and is used to set the result of
- ** sqlite3OsCurrentTime() during testing.
++** Purge the winShmNodeList list of all entries with winShmNode.nRef==0.
++**
++** This is not a VFS shared-memory method; it is a utility function called
++** by VFS shared-memory methods.
 +*/
- #ifdef SQLITE_TEST
- int sqlite3_current_time = 0;  /* Fake system time in seconds since 1970. */
- #endif
++static void winShmPurge(void){
++  winShmNode **pp;
++  winShmNode *p;
++  assert( winShmMutexHeld() );
++  pp = &winShmNodeList;
++  while( (p = *pp)!=0 ){
++    if( p->nRef==0 ){
++      if( p->mutex ) sqlite3_mutex_free(p->mutex);
++      if( p->mutexBuf ) sqlite3_mutex_free(p->mutexBuf);
++      if( p->pMMapBuf ){
++        UnmapViewOfFile(p->pMMapBuf);
++      }
++      if( INVALID_HANDLE_VALUE != p->hMap ){
++        CloseHandle(p->hMap);
++      }
++      if( p->hFile.h != INVALID_HANDLE_VALUE ) {
++        winClose((sqlite3_file *)&p->hFile);
++      }
++      *pp = p->pNext;
++      sqlite3_free(p);
++    }else{
++      pp = &p->pNext;
++    }
++  }
++}
++
++/* Forward references to VFS methods */
++static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*);
++static int winDelete(sqlite3_vfs *,const char*,int);
 +
 +/*
- ** Find the current time (in Universal Coordinated Time).  Write into *piNow
- ** the current time and date as a Julian Day number times 86_400_000.  In
- ** other words, write into *piNow the number of milliseconds since the Julian
- ** epoch of noon in Greenwich on November 24, 4714 B.C according to the
- ** proleptic Gregorian calendar.
++** Open a shared-memory area.  This particular implementation uses
++** mmapped files.
 +**
- ** On success, return 0.  Return 1 if the time and date cannot be found.
++** zName is a filename used to identify the shared-memory area.  The
++** implementation does not (and perhaps should not) use this name
++** directly, but rather use it as a template for finding an appropriate
++** name for the shared-memory storage.  In this implementation, the
++** string "-index" is appended to zName and used as the name of the
++** mmapped file.
++**
++** When opening a new shared-memory file, if no other instances of that
++** file are currently open, in this process or in other processes, then
++** the file must be truncated to zero length or have its header cleared.
 +*/
- static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
-   /* FILETIME structure is a 64-bit value representing the number of 
-      100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). 
++static int winShmOpen(
++  sqlite3_file *fd      /* The file to which to attach shared memory */
++){
++  struct winFile *pDbFd;             /* Database to which to attach SHM */
++  struct winShm *p;                  /* The connection to be opened */
++  struct winShmNode *pShmNode = 0;   /* The underlying mmapped file */
++  int rc;                            /* Result code */
++  struct winShmNode *pNew;           /* Newly allocated winShmNode */
++  int nName;                         /* Size of zName in bytes */
++
++  pDbFd = (winFile*)fd;
++  assert( pDbFd->pShm==0 );    /* Not previously opened */
++
++  /* Allocate space for the new sqlite3_shm object.  Also speculatively
++  ** allocate space for a new winShmNode and filename.
 +  */
-   FILETIME ft;
-   static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000;
- #ifdef SQLITE_TEST
-   static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
- #endif
-   /* 2^32 - to avoid use of LL and warnings in gcc */
-   static const sqlite3_int64 max32BitValue = 
-       (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + (sqlite3_int64)294967296;
++  p = sqlite3_malloc( sizeof(*p) );
++  if( p==0 ) return SQLITE_NOMEM;
++  memset(p, 0, sizeof(*p));
++  nName = sqlite3Strlen30(pDbFd->zPath);
++  pNew = sqlite3_malloc( sizeof(*pShmNode) + nName + 15 );
++  if( pNew==0 ){
++    sqlite3_free(p);
++    return SQLITE_NOMEM;
++  }
++  memset(pNew, 0, sizeof(*pNew));
++  pNew->zFilename = (char*)&pNew[1];
++  sqlite3_snprintf(nName+15, pNew->zFilename, "%s-wal-index", pDbFd->zPath);
 +
- #if SQLITE_OS_WINCE
-   SYSTEMTIME time;
-   GetSystemTime(&time);
-   /* if SystemTimeToFileTime() fails, it returns zero. */
-   if (!SystemTimeToFileTime(&time,&ft)){
-     return 1;
++  /* Look to see if there is an existing winShmNode that can be used.
++  ** If no matching winShmNode currently exists, create a new one.
++  */
++  winShmEnterMutex();
++  for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){
++    /* TBD need to come up with better match here.  Perhaps
++    ** use FILE_ID_BOTH_DIR_INFO Structure.
++    */
++    if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break;
 +  }
- #else
-   GetSystemTimeAsFileTime( &ft );
++  if( pShmNode ){
++    sqlite3_free(pNew);
++  }else{
++    pShmNode = pNew;
++    pNew = 0;
++    pShmNode->pMMapBuf = NULL;
++    pShmNode->hMap = INVALID_HANDLE_VALUE;
++    ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE;
++    pShmNode->pNext = winShmNodeList;
++    winShmNodeList = pShmNode;
++
++    pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
++    if( pShmNode->mutex==0 ){
++      rc = SQLITE_NOMEM;
++      goto shm_open_err;
++    }
++    pShmNode->mutexBuf = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
++    if( pShmNode->mutexBuf==0 ){
++      rc = SQLITE_NOMEM;
++      goto shm_open_err;
++    }
++    rc = winOpen(pDbFd->pVfs,
++                 pShmNode->zFilename,             /* Name of the file (UTF-8) */
++                 (sqlite3_file*)&pShmNode->hFile,  /* File handle here */
++                 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, /* Mode flags */
++                 0);
++    if( SQLITE_OK!=rc ){
++      rc = SQLITE_CANTOPEN_BKPT;
++      goto shm_open_err;
++    }
++
++    /* Check to see if another process is holding the dead-man switch.
++    ** If not, truncate the file to zero length. 
++    */
++    if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS)==SQLITE_OK ){
++      rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
++    }
++    if( rc==SQLITE_OK ){
++      rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS);
++    }
++    if( rc ) goto shm_open_err;
++  }
++
++  /* Make the new connection a child of the winShmNode */
++  p->pShmNode = pShmNode;
++  p->pNext = pShmNode->pFirst;
++#ifdef SQLITE_DEBUG
++  p->id = pShmNode->nextShmId++;
 +#endif
++  pShmNode->pFirst = p;
++  pShmNode->nRef++;
++  pDbFd->pShm = p;
++  winShmLeaveMutex();
++  return SQLITE_OK;
 +
-   *piNow = winFiletimeEpoch +
-             ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) + 
-                (sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)1000;
++  /* Jump here on any error */
++shm_open_err:
++  winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS);
++  winShmPurge();                 /* This call frees pShmNode if required */
++  sqlite3_free(p);
++  sqlite3_free(pNew);
++  winShmLeaveMutex();
++  return rc;
++}
 +
- #ifdef SQLITE_TEST
-   if( sqlite3_current_time ){
-     *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
++/*
++** Close a connection to shared-memory.  Delete the underlying 
++** storage if deleteFlag is true.
++*/
++static int winShmClose(
++  sqlite3_file *fd,          /* Database holding shared memory */
++  int deleteFlag             /* Delete after closing if true */
++){
++  winFile *pDbFd;       /* Database holding shared-memory */
++  winShm *p;            /* The connection to be closed */
++  winShmNode *pShmNode; /* The underlying shared-memory file */
++  winShm **pp;          /* For looping over sibling connections */
++
++  pDbFd = (winFile*)fd;
++  p = pDbFd->pShm;
++  pShmNode = p->pShmNode;
++
++  /* Verify that the connection being closed holds no locks */
++  assert( p->exclMask==0 );
++  assert( p->sharedMask==0 );
++
++  /* Remove connection p from the set of connections associated
++  ** with pShmNode */
++  sqlite3_mutex_enter(pShmNode->mutex);
++  for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
++  *pp = p->pNext;
++
++  /* Free the connection p */
++  sqlite3_free(p);
++  pDbFd->pShm = 0;
++  sqlite3_mutex_leave(pShmNode->mutex);
++
++  /* If pShmNode->nRef has reached 0, then close the underlying
++  ** shared-memory file, too */
++  winShmEnterMutex();
++  assert( pShmNode->nRef>0 );
++  pShmNode->nRef--;
++  if( pShmNode->nRef==0 ){
++    if( deleteFlag ) winDelete(pDbFd->pVfs, pShmNode->zFilename, 0);
++    winShmPurge();
 +  }
- #endif
-   UNUSED_PARAMETER(pVfs);
-   return 0;
++  winShmLeaveMutex();
++
++  return SQLITE_OK;
 +}
 +
 +/*
- ** Find the current time (in Universal Coordinated Time).  Write the
- ** current time and date as a Julian Day number into *prNow and
- ** return 0.  Return 1 if the time and date cannot be found.
++** Query and/or changes the size of the underlying storage for
++** a shared-memory segment.  The reqSize parameter is the new size
++** of the underlying storage, or -1 to do just a query.  The size
++** of the underlying storage (after resizing if resizing occurs) is
++** written into pNewSize.
++**
++** This routine does not (necessarily) change the size of the mapping 
++** of the underlying storage into memory.  Use xShmGet() to change
++** the mapping size.
++**
++** The reqSize parameter is the minimum size requested.  The implementation
++** is free to expand the storage to some larger amount if it chooses.
 +*/
- int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
-   int rc;
-   sqlite3_int64 i;
-   rc = winCurrentTimeInt64(pVfs, &i);
-   if( !rc ){
-     *prNow = i/86400000.0;
++static int winShmSize(
++  sqlite3_file *fd,         /* Database holding the shared memory */
++  int reqSize,              /* Requested size.  -1 for query only */
++  int *pNewSize             /* Write new size here */
++){
++  winFile *pDbFd = (winFile*)fd;
++  winShm *p = pDbFd->pShm;
++  winShmNode *pShmNode = p->pShmNode;
++  int rc = SQLITE_OK;
++
++  *pNewSize = 0;
++  if( reqSize>=0 ){
++    sqlite3_int64 sz;
++    rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz);
++    if( SQLITE_OK==rc ){
++      reqSize = (reqSize + SQLITE_WIN_SHM_INCR - 1)/SQLITE_WIN_SHM_INCR;
++      reqSize *= SQLITE_WIN_SHM_INCR;
++      if( reqSize>sz ){
++        rc = winTruncate((sqlite3_file *)&pShmNode->hFile, reqSize);
++      }
++    }
++  }
++  if( SQLITE_OK==rc ){
++    sqlite3_int64 sz;
++    rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz);
++    if( SQLITE_OK==rc ){
++      *pNewSize = (int)sz;
++    }else{
++      rc = SQLITE_IOERR;
++    }
 +  }
 +  return rc;
 +}
 +
++
 +/*
- ** The idea is that this function works like a combination of
- ** GetLastError() and FormatMessage() on windows (or errno and
- ** strerror_r() on unix). After an error is returned by an OS
- ** function, SQLite calls this function with zBuf pointing to
- ** a buffer of nBuf bytes. The OS layer should populate the
- ** buffer with a nul-terminated UTF-8 encoded error message
- ** describing the last IO error to have occurred within the calling
- ** thread.
++** Map the shared storage into memory.  The minimum size of the
++** mapping should be reqMapSize if reqMapSize is positive.  If
++** reqMapSize is zero or negative, the implementation can choose
++** whatever mapping size is convenient.
 +**
- ** If the error message is too large for the supplied buffer,
- ** it should be truncated. The return value of xGetLastError
- ** is zero if the error message fits in the buffer, or non-zero
- ** otherwise (if the message was truncated). If non-zero is returned,
- ** then it is not necessary to include the nul-terminator character
- ** in the output buffer.
++** *ppBuf is made to point to the memory which is a mapping of the
++** underlying storage.  A mutex is acquired to prevent other threads
++** from running while *ppBuf is in use in order to prevent other threads
++** remapping *ppBuf out from under this thread.  The winShmRelease()
++** call will release the mutex.  However, if the lock state is CHECKPOINT,
++** the mutex is not acquired because CHECKPOINT will never remap the
++** buffer.  RECOVER might remap, though, so CHECKPOINT will acquire
++** the mutex if and when it promotes to RECOVER.
 +**
- ** Not supplying an error message will have no adverse effect
- ** on SQLite. It is fine to have an implementation that never
- ** returns an error message:
++** RECOVER needs to be atomic.  The same mutex that prevents *ppBuf from
++** being remapped also prevents more than one thread from being in
++** RECOVER at a time.  But, RECOVER sometimes wants to remap itself.
++** To prevent RECOVER from losing its lock while remapping, the
++** mutex is not released by winShmRelease() when in RECOVER.
 +**
- **   int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
- **     assert(zBuf[0]=='\0');
- **     return 0;
- **   }
++** *pNewMapSize is set to the size of the mapping.
 +**
- ** However if an error message is supplied, it will be incorporated
- ** by sqlite into the error message available to the user using
- ** sqlite3_errmsg(), possibly making IO errors easier to debug.
++** *ppBuf and *pNewMapSize might be NULL and zero if no space has
++** yet been allocated to the underlying storage.
 +*/
- static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
-   UNUSED_PARAMETER(pVfs);
-   return getLastErrorMsg(nBuf, zBuf);
- }
++static int winShmGet(
++  sqlite3_file *fd,        /* The database file holding the shared memory */
++  int reqMapSize,          /* Requested size of mapping. -1 means don't care */
++  int *pNewMapSize,        /* Write new size of mapping here */
++  void **ppBuf             /* Write mapping buffer origin here */
++){
++  winFile *pDbFd = (winFile*)fd;
++  winShm *p = pDbFd->pShm;
++  winShmNode *pShmNode = p->pShmNode;
++  int rc = SQLITE_OK;
 +
- #ifndef SQLITE_OMIT_WAL
++  if( p->lockState!=SQLITE_SHM_CHECKPOINT && p->hasMutexBuf==0 ){
++    assert( sqlite3_mutex_notheld(pShmNode->mutex) );
++    sqlite3_mutex_enter(pShmNode->mutexBuf);
++    p->hasMutexBuf = 1;
++  }
++  sqlite3_mutex_enter(pShmNode->mutex);
++  if( pShmNode->szMap==0 || reqMapSize>pShmNode->szMap ){
++    int actualSize;
++    if( winShmSize(fd, -1, &actualSize)==SQLITE_OK
++     && reqMapSize<actualSize
++    ){
++      reqMapSize = actualSize;
++    }
++    if( pShmNode->pMMapBuf ){
++      if( !UnmapViewOfFile(pShmNode->pMMapBuf) ){
++        pShmNode->lastErrno = GetLastError();
++        rc = SQLITE_IOERR;
++      }
++      CloseHandle(pShmNode->hMap);
++      pShmNode->hMap = INVALID_HANDLE_VALUE;
++    }
++    if( SQLITE_OK == rc ){
++      pShmNode->pMMapBuf = 0;
++      if( reqMapSize == 0 ){
++        /* can't create 0 byte file mapping in Windows */
++        pShmNode->szMap = 0;
++      }else{
++        /* create the file mapping object */
++        if( INVALID_HANDLE_VALUE == pShmNode->hMap ){
++          /* TBD provide an object name to each file
++          ** mapping so it can be re-used across processes.
++          */
++          pShmNode->hMap = CreateFileMapping(pShmNode->hFile.h,
++                                          NULL,
++                                          PAGE_READWRITE,
++                                          0,
++                                          reqMapSize,
++                                          NULL);
++        }
++        if( NULL==pShmNode->hMap ){
++          pShmNode->lastErrno = GetLastError();
++          rc = SQLITE_IOERR;
++          pShmNode->szMap = 0;
++          pShmNode->hMap = INVALID_HANDLE_VALUE;
++        }else{
++          pShmNode->pMMapBuf = MapViewOfFile(pShmNode->hMap,
++                                          FILE_MAP_WRITE | FILE_MAP_READ,
++                                          0,
++                                          0,
++                                          reqMapSize);
++          if( !pShmNode->pMMapBuf ){
++            pShmNode->lastErrno = GetLastError();
++            rc = SQLITE_IOERR;
++            pShmNode->szMap = 0;
++          }else{
++            pShmNode->szMap = reqMapSize;
++          }
++        }
++      }
++    }
++  }
++  *pNewMapSize = pShmNode->szMap;
++  *ppBuf = pShmNode->pMMapBuf;
++  sqlite3_mutex_leave(pShmNode->mutex);
++  return rc;
++}
 +
 +/*
- ** Helper functions to obtain and relinquish the global mutex. The
- ** global mutex is used to protect the winLockInfo objects used by 
- ** this file, all of which may be shared by multiple threads.
++** Release the lock held on the shared memory segment so that other
++** threads are free to resize it if necessary.
 +**
- ** Function winShmMutexHeld() is used to assert() that the global mutex 
- ** is held when required. This function is only used as part of assert() 
- ** statements. e.g.
++** If the lock is not currently held, this routine is a harmless no-op.
 +**
- **   winShmEnterMutex()
- **     assert( winShmMutexHeld() );
- **   winEnterLeave()
++** If the shared-memory object is in lock state RECOVER, then we do not
++** really want to release the lock, so in that case too, this routine
++** is a no-op.
 +*/
- static void winShmEnterMutex(void){
-   sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
- }
- static void winShmLeaveMutex(void){
-   sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
++static int winShmRelease(sqlite3_file *fd){
++  winFile *pDbFd = (winFile*)fd;
++  winShm *p = pDbFd->pShm;
++  if( p->hasMutexBuf && p->lockState!=SQLITE_SHM_RECOVER ){
++    winShmNode *pShmNode = p->pShmNode;
++    assert( sqlite3_mutex_notheld(pShmNode->mutex) );
++    sqlite3_mutex_leave(pShmNode->mutexBuf);
++    p->hasMutexBuf = 0;
++  }
++  return SQLITE_OK;
 +}
++
++/*
++** Symbolic names for LOCK states used for debugging.
++*/
 +#ifdef SQLITE_DEBUG
- static int winShmMutexHeld(void) {
-   return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
- }
++static const char *azLkName[] = {
++  "UNLOCK",
++  "READ",
++  "READ_FULL",
++  "WRITE",
++  "PENDING",
++  "CHECKPOINT",
++  "RECOVER"
++};
 +#endif
 +
- /* Forward reference */
- typedef struct winShm winShm;
- typedef struct winShmFile winShmFile;
 +
 +/*
- ** Object used to represent a single file opened and mmapped to provide
- ** shared memory.  When multiple threads all reference the same
- ** log-summary, each thread has its own winFile object, but they all
- ** point to a single instance of this object.  In other words, each
- ** log-summary is opened only once per process.
- **
- ** winShmMutexHeld() must be true when creating or destroying
- ** this object or while reading or writing the following fields:
- **
- **      nRef
- **      pNext 
- **
- ** The following fields are read-only after the object is created:
- ** 
- **      fid
- **      zFilename
- **
- ** Either winShmFile.mutex must be held or winShmFile.nRef==0 and
- ** winShmMutexHeld() is true when reading or writing any other field
- ** in this structure.
- **
- ** To avoid deadlocks, mutex and mutexBuf are always released in the
- ** reverse order that they are acquired.  mutexBuf is always acquired
- ** first and released last.  This invariant is check by asserting
- ** sqlite3_mutex_notheld() on mutex whenever mutexBuf is acquired or
- ** released.
++** Change the lock state for a shared-memory segment.
 +*/
- struct winShmFile {
-   sqlite3_mutex *mutex;      /* Mutex to access this object */
-   sqlite3_mutex *mutexBuf;   /* Mutex to access zBuf[] */
-   char *zFilename;           /* Name of the file */
-   winFile hFile;             /* File handle from winOpen */
-   HANDLE hMap;               /* File handle from CreateFileMapping */
-   DWORD lastErrno;           /* The Windows errno from the last I/O error */
-   int szMap;                 /* Size of the mapping of file into memory */
-   char *pMMapBuf;            /* Where currently mmapped().  NULL if unmapped */
-   int nRef;                  /* Number of winShm objects pointing to this */
-   winShm *pFirst;            /* All winShm objects pointing to this */
-   winShmFile *pNext;         /* Next in list of all winShmFile objects */
- #ifdef SQLITE_DEBUG
-   u8 exclMask;               /* Mask of exclusive locks held */
-   u8 sharedMask;             /* Mask of shared locks held */
-   u8 nextShmId;              /* Next available winShm.id value */
- #endif
- };
++static int winShmLock(
++  sqlite3_file *fd,          /* Database holding the shared memory */
++  int desiredLock,           /* One of SQLITE_SHM_xxxxx locking states */
++  int *pGotLock              /* The lock you actually got */
++){
++  winFile *pDbFd = (winFile*)fd;
++  winShm *p = pDbFd->pShm;
++  winShmNode *pShmNode = p->pShmNode;
++  int rc = SQLITE_PROTOCOL;
++
++  /* Note that SQLITE_SHM_READ_FULL and SQLITE_SHM_PENDING are never
++  ** directly requested; they are side effects from requesting
++  ** SQLITE_SHM_READ and SQLITE_SHM_CHECKPOINT, respectively.
++  */
++  assert( desiredLock==SQLITE_SHM_UNLOCK
++       || desiredLock==SQLITE_SHM_READ
++       || desiredLock==SQLITE_SHM_WRITE
++       || desiredLock==SQLITE_SHM_CHECKPOINT
++       || desiredLock==SQLITE_SHM_RECOVER );
++
++  /* Return directly if this is just a lock state query, or if
++  ** the connection is already in the desired locking state.
++  */
++  if( desiredLock==p->lockState
++   || (desiredLock==SQLITE_SHM_READ && p->lockState==SQLITE_SHM_READ_FULL)
++  ){
++    OSTRACE(("SHM-LOCK %d shmid-%d, pid-%d request %s and got %s\n",
++             pShmNode->hFile.h,
++             p->id, (int)GetCurrentProcessId(), azLkName[desiredLock],
++             azLkName[p->lockState]));
++    if( pGotLock ) *pGotLock = p->lockState;
++    return SQLITE_OK;
++  }
++
++  OSTRACE(("SHM-LOCK %d shmid-%d, pid-%d request %s->%s\n",
++           pShmNode->hFile.h,
++           p->id, (int)GetCurrentProcessId(), azLkName[p->lockState], 
++           azLkName[desiredLock]));
++  
++  if( desiredLock==SQLITE_SHM_RECOVER && !p->hasMutexBuf ){
++    assert( sqlite3_mutex_notheld(pShmNode->mutex) );
++    sqlite3_mutex_enter(pShmNode->mutexBuf);
++    p->hasMutexBuf = 1;
++  }
++  sqlite3_mutex_enter(pShmNode->mutex);
++  switch( desiredLock ){
++    case SQLITE_SHM_UNLOCK: {
++      assert( p->lockState!=SQLITE_SHM_RECOVER );
++      winShmUnlock(pShmNode, p, WIN_SHM_A|WIN_SHM_B|WIN_SHM_C|WIN_SHM_D);
++      rc = SQLITE_OK;
++      p->lockState = SQLITE_SHM_UNLOCK;
++      break;
++    }
++    case SQLITE_SHM_READ: {
++      if( p->lockState==SQLITE_SHM_UNLOCK ){
++        int nAttempt;
++        rc = SQLITE_BUSY;
++        assert( p->lockState==SQLITE_SHM_UNLOCK );
++        for(nAttempt=0; nAttempt<5 && rc==SQLITE_BUSY; nAttempt++){
++          rc = winShmSharedLock(pShmNode, p, WIN_SHM_A|WIN_SHM_B);
++          if( rc==SQLITE_BUSY ){
++            rc = winShmSharedLock(pShmNode, p, WIN_SHM_D);
++            if( rc==SQLITE_OK ){
++              p->lockState = SQLITE_SHM_READ_FULL;
++            }
++          }else{
++            winShmUnlock(pShmNode, p, WIN_SHM_B);
++            p->lockState = SQLITE_SHM_READ;
++          }
++        }
++      }else{
++       assert( p->lockState==SQLITE_SHM_WRITE
++               || p->lockState==SQLITE_SHM_RECOVER );
++        rc = winShmSharedLock(pShmNode, p, WIN_SHM_A);
++        winShmUnlock(pShmNode, p, WIN_SHM_C|WIN_SHM_D);
++        p->lockState = SQLITE_SHM_READ;
++      }
++      break;
++    }
++    case SQLITE_SHM_WRITE: {
++      assert( p->lockState==SQLITE_SHM_READ 
++              || p->lockState==SQLITE_SHM_READ_FULL );
++      rc = winShmExclusiveLock(pShmNode, p, WIN_SHM_C|WIN_SHM_D);
++      if( rc==SQLITE_OK ){
++        p->lockState = SQLITE_SHM_WRITE;
++      }
++      break;
++    }
++    case SQLITE_SHM_CHECKPOINT: {
++      assert( p->lockState==SQLITE_SHM_UNLOCK
++           || p->lockState==SQLITE_SHM_PENDING
++      );
++      if( p->lockState==SQLITE_SHM_UNLOCK ){
++        rc = winShmExclusiveLock(pShmNode, p, WIN_SHM_B|WIN_SHM_C);
++        if( rc==SQLITE_OK ){
++          p->lockState = SQLITE_SHM_PENDING;
++        }
++      }
++      if( p->lockState==SQLITE_SHM_PENDING ){
++        rc = winShmExclusiveLock(pShmNode, p, WIN_SHM_A);
++        if( rc==SQLITE_OK ){
++          p->lockState = SQLITE_SHM_CHECKPOINT;
++        }
++      }
++      break;
++    }
++    default: {
++      assert( desiredLock==SQLITE_SHM_RECOVER );
++      assert( p->lockState==SQLITE_SHM_READ
++           || p->lockState==SQLITE_SHM_READ_FULL
++      );
++      assert( sqlite3_mutex_held(pShmNode->mutexBuf) );
++      rc = winShmExclusiveLock(pShmNode, p, WIN_SHM_C);
++      if( rc==SQLITE_OK ){
++        p->lockState = SQLITE_SHM_RECOVER;
++      }
++      break;
++    }
++  }
++  sqlite3_mutex_leave(pShmNode->mutex);
++  OSTRACE(("SHM-LOCK %d shmid-%d, pid-%d got %s\n",
++           pShmNode->hFile.h, 
++           p->id, (int)GetCurrentProcessId(), azLkName[p->lockState]));
++  if( pGotLock ) *pGotLock = p->lockState;
++  return rc;
++}
 +
++#else
++# define winShmOpen    0
++# define winShmSize    0
++# define winShmGet     0
++# define winShmRelease 0
++# define winShmLock    0
++# define winShmClose   0
++#endif /* #ifndef SQLITE_OMIT_WAL */
 +/*
- ** A global array of all winShmFile objects.
- **
- ** The winShmMutexHeld() must be true while reading or writing this list.
- */
- static winShmFile *winShmFileList = 0;
++***************************** End Shared Memory *****************************
++****************************************************************************/
 +
  /*
- ** Structure used internally by this VFS to record the state of an
- ** open shared memory connection.
- **
- ** winShm.pFile->mutex must be held while reading or writing the
- ** winShm.pNext and winShm.locks[] elements.
- **
- ** The winShm.pFile element is initialized when the object is created
- ** and is read-only thereafter.
+ ** This vector defines all the methods that can operate on an
+ ** sqlite3_file for win32.
  */
- struct winShm {
-   winShmFile *pFile;         /* The underlying winShmFile object */
-   winShm *pNext;             /* Next winShm with the same winShmFile */
-   u8 lockState;              /* Current lock state */
-   u8 hasMutex;               /* True if holding the winShmFile mutex */
-   u8 hasMutexBuf;            /* True if holding pFile->mutexBuf */
-   u8 sharedMask;             /* Mask of shared locks held */
-   u8 exclMask;               /* Mask of exclusive locks held */
- #ifdef SQLITE_DEBUG
-   u8 id;                     /* Id of this connection with its winShmFile */
- #endif
+ static const sqlite3_io_methods winIoMethod = {
 -  1,                        /* iVersion */
++  2,                        /* iVersion */
+   winClose,
+   winRead,
+   winWrite,
+   winTruncate,
+   winSync,
+   winFileSize,
+   winLock,
+   winUnlock,
+   winCheckReservedLock,
+   winFileControl,
+   winSectorSize,
 -  winDeviceCharacteristics
++  winDeviceCharacteristics,
++  winShmOpen,              /* xShmOpen */
++  winShmSize,              /* xShmSize */
++  winShmGet,               /* xShmGet */
++  winShmRelease,           /* xShmRelease */
++  winShmLock,              /* xShmLock */
++  winShmClose              /* xShmClose */
  };
  
- /*
- ** Size increment by which shared memory grows
- */
- #define SQLITE_WIN_SHM_INCR  4096
+ /***************************************************************************
+ ** Here ends the I/O methods that form the sqlite3_io_methods object.
+ **
+ ** The next block of code implements the VFS methods.
+ ****************************************************************************/
  
  /*
- ** Constants used for locking
+ ** Convert a UTF-8 filename into whatever form the underlying
+ ** operating system wants filenames in.  Space to hold the result
+ ** is obtained from malloc and must be freed by the calling
+ ** function.
  */
- #define WIN_SHM_BASE      32        /* Byte offset of the first lock byte */
- #define WIN_SHM_DMS       0x01      /* Mask for Dead-Man-Switch lock */
- #define WIN_SHM_A         0x10      /* Mask for region locks... */
- #define WIN_SHM_B         0x20
- #define WIN_SHM_C         0x40
- #define WIN_SHM_D         0x80
- #ifdef SQLITE_DEBUG
- /*
- ** Return a pointer to a nul-terminated string in static memory that
- ** describes a locking mask.  The string is of the form "MSABCD" with
- ** each character representing a lock.  "M" for MUTEX, "S" for DMS, 
- ** and "A" through "D" for the region locks.  If a lock is held, the
- ** letter is shown.  If the lock is not held, the letter is converted
- ** to ".".
- **
- ** This routine is for debugging purposes only and does not appear
- ** in a production build.
+ static void *convertUtf8Filename(const char *zFilename){
+   void *zConverted = 0;
+   if( isNT() ){
+     zConverted = utf8ToUnicode(zFilename);
+ /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
  */
- static const char *winShmLockString(u8 mask){
-   static char zBuf[48];
-   static int iBuf = 0;
-   char *z;
-   z = &zBuf[iBuf];
-   iBuf += 8;
-   if( iBuf>=sizeof(zBuf) ) iBuf = 0;
-   z[0] = (mask & WIN_SHM_DMS)   ? 'S' : '.';
-   z[1] = (mask & WIN_SHM_A)     ? 'A' : '.';
-   z[2] = (mask & WIN_SHM_B)     ? 'B' : '.';
-   z[3] = (mask & WIN_SHM_C)     ? 'C' : '.';
-   z[4] = (mask & WIN_SHM_D)     ? 'D' : '.';
-   z[5] = 0;
-   return z;
+ #if SQLITE_OS_WINCE==0
+   }else{
+     zConverted = utf8ToMbcs(zFilename);
+ #endif
+   }
+   /* caller will handle out of memory */
+   return zConverted;
  }
- #endif /* SQLITE_DEBUG */
  
  /*
- ** Apply posix advisory locks for all bytes identified in lockMask.
- **
- ** lockMask might contain multiple bits but all bits are guaranteed
- ** to be contiguous.
- **
- ** Locks block if the mask is exactly WIN_SHM_C and are non-blocking
- ** otherwise.
+ ** Create a temporary file name in zBuf.  zBuf must be big enough to
+ ** hold at pVfs->mxPathname characters.
  */
- #define _SHM_UNLCK  1
- #define _SHM_RDLCK  2
- #define _SHM_WRLCK  3
- static int winShmSystemLock(
-   winShmFile *pFile,    /* Apply locks to this open shared-memory segment */
-   int lockType,         /* _SHM_UNLCK, _SHM_RDLCK, or _SHM_WRLCK */
-   u8 lockMask           /* Which bytes to lock or unlock */
- ){
-   OVERLAPPED ovlp;
-   DWORD dwFlags;
-   int nBytes;           /* Number of bytes to lock */
-   int i;                /* Offset into the locking byte range */
-   int rc = 0;           /* Result code form Lock/UnlockFileEx() */
-   u8 mask;              /* Mask of bits in lockMask */
-   /* Access to the winShmFile object is serialized by the caller */
-   assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
-   /* Initialize the locking parameters */
-   if( lockMask==WIN_SHM_C && lockType!=_SHM_UNLCK ){
-     dwFlags = 0;
-     OSTRACE(("SHM-LOCK %d requesting blocking lock %s\n", 
-              pFile->hFile.h,
-              winShmLockString(lockMask)));
+ static int getTempname(int nBuf, char *zBuf){
+   static char zChars[] =
+     "abcdefghijklmnopqrstuvwxyz"
+     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+     "0123456789";
+   size_t i, j;
+   char zTempPath[MAX_PATH+1];
+   if( sqlite3_temp_directory ){
+     sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory);
+   }else if( isNT() ){
+     char *zMulti;
+     WCHAR zWidePath[MAX_PATH];
+     GetTempPathW(MAX_PATH-30, zWidePath);
+     zMulti = unicodeToUtf8(zWidePath);
+     if( zMulti ){
+       sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti);
+       free(zMulti);
+     }else{
+       return SQLITE_NOMEM;
+     }
+ /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
+ ** Since the ASCII version of these Windows API do not exist for WINCE,
+ ** it's important to not reference them for WINCE builds.
+ */
+ #if SQLITE_OS_WINCE==0
    }else{
-     dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
-     OSTRACE(("SHM-LOCK %d requesting %s %s\n", 
-              pFile->hFile.h,
-              lockType!=_SHM_UNLCK ? "lock" : "unlock", 
-              winShmLockString(lockMask)));
+     char *zUtf8;
+     char zMbcsPath[MAX_PATH];
+     GetTempPathA(MAX_PATH-30, zMbcsPath);
+     zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath);
+     if( zUtf8 ){
+       sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8);
+       free(zUtf8);
+     }else{
+       return SQLITE_NOMEM;
+     }
+ #endif
    }
-   if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
-   /* Find the first bit in lockMask that is set */
-   for(i=0, mask=0x01; mask!=0 && (lockMask&mask)==0; mask <<= 1, i++){}
-   assert( mask!=0 );
-   memset(&ovlp, 0, sizeof(OVERLAPPED));
-   ovlp.Offset = i+WIN_SHM_BASE;
-   nBytes = 1;
-   /* Extend the locking range for each additional bit that is set */
-   mask <<= 1;
-   while( mask!=0 && (lockMask & mask)!=0 ){
-     nBytes++;
-     mask <<= 1;
+   for(i=sqlite3Strlen30(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
+   zTempPath[i] = 0;
+   sqlite3_snprintf(nBuf-30, zBuf,
+                    "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath);
+   j = sqlite3Strlen30(zBuf);
+   sqlite3_randomness(20, &zBuf[j]);
+   for(i=0; i<20; i++, j++){
+     zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
    }
+   zBuf[j] = 0;
+   OSTRACE(("TEMP FILENAME: %s\n", zBuf));
+   return SQLITE_OK; 
+ }
  
-   /* Verify that all bits set in lockMask are contiguous */
-   assert( mask==0 || (lockMask & ~(mask | (mask-1)))==0 );
+ /*
+ ** The return value of getLastErrorMsg
+ ** is zero if the error message fits in the buffer, or non-zero
+ ** otherwise (if the message was truncated).
+ */
+ static int getLastErrorMsg(int nBuf, char *zBuf){
+   /* FormatMessage returns 0 on failure.  Otherwise it
+   ** returns the number of TCHARs written to the output
+   ** buffer, excluding the terminating null char.
+   */
+   DWORD error = GetLastError();
+   DWORD dwLen = 0;
+   char *zOut = 0;
  
-   /* Release/Acquire the system-level lock */
-   if( lockType==_SHM_UNLCK ){
-     for(i=0; i<nBytes; i++, ovlp.Offset++){
-       rc = UnlockFileEx(pFile->hFile.h, 0, 1, 0, &ovlp);
-       if( !rc ) break;
+   if( isNT() ){
+     WCHAR *zTempWide = NULL;
+     dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+                            NULL,
+                            error,
+                            0,
+                            (LPWSTR) &zTempWide,
+                            0,
+                            0);
+     if( dwLen > 0 ){
+       /* allocate a buffer and convert to UTF8 */
+       zOut = unicodeToUtf8(zTempWide);
+       /* free the system buffer allocated by FormatMessage */
+       LocalFree(zTempWide);
      }
+ /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
+ ** Since the ASCII version of these Windows API do not exist for WINCE,
+ ** it's important to not reference them for WINCE builds.
+ */
+ #if SQLITE_OS_WINCE==0
    }else{
-     /* release old individual byte locks (if any)
-     ** and set new individual byte locks */
-     for(i=0; i<nBytes; i++, ovlp.Offset++){
-       UnlockFileEx(pFile->hFile.h, 0, 1, 0, &ovlp);
-       rc = LockFileEx(pFile->hFile.h, dwFlags, 0, 1, 0, &ovlp);
-       if( !rc ) break;
-     }
-   }
-   if( !rc ){
-     OSTRACE(("SHM-LOCK %d %s ERROR 0x%08lx\n", 
-              pFile->hFile.h,
-              lockType==_SHM_UNLCK ? "UnlockFileEx" : "LockFileEx", GetLastError()));
-     /* release individual byte locks (if any) */
-     ovlp.Offset-=i;
-     for(i=0; i<nBytes; i++, ovlp.Offset++){
-       UnlockFileEx(pFile->hFile.h, 0, 1, 0, &ovlp);
+     char *zTemp = NULL;
+     dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+                            NULL,
+                            error,
+                            0,
+                            (LPSTR) &zTemp,
+                            0,
+                            0);
+     if( dwLen > 0 ){
+       /* allocate a buffer and convert to UTF8 */
+       zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
+       /* free the system buffer allocated by FormatMessage */
+       LocalFree(zTemp);
      }
+ #endif
    }
-   rc = (rc!=0) ? SQLITE_OK : SQLITE_BUSY;
-   /* Update the global lock state and do debug tracing */
- #ifdef SQLITE_DEBUG
-   OSTRACE(("SHM-LOCK %d ", pFile->hFile.h));
-   if( rc==SQLITE_OK ){
-     if( lockType==_SHM_UNLCK ){
-       OSTRACE(("unlock ok"));
-       pFile->exclMask &= ~lockMask;
-       pFile->sharedMask &= ~lockMask;
-     }else if( lockType==_SHM_RDLCK ){
-       OSTRACE(("read-lock ok"));
-       pFile->exclMask &= ~lockMask;
-       pFile->sharedMask |= lockMask;
-     }else{
-       assert( lockType==_SHM_WRLCK );
-       OSTRACE(("write-lock ok"));
-       pFile->exclMask |= lockMask;
-       pFile->sharedMask &= ~lockMask;
-     }
+   if( 0 == dwLen ){
+     sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error);
    }else{
-     if( lockType==_SHM_UNLCK ){
-       OSTRACE(("unlock failed"));
-     }else if( lockType==_SHM_RDLCK ){
-       OSTRACE(("read-lock failed"));
-     }else{
-       assert( lockType==_SHM_WRLCK );
-       OSTRACE(("write-lock failed"));
-     }
+     /* copy a maximum of nBuf chars to output buffer */
+     sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
+     /* free the UTF8 buffer */
+     free(zOut);
    }
-   OSTRACE((" - change requested %s - afterwards %s:%s\n",
-            winShmLockString(lockMask),
-            winShmLockString(pFile->sharedMask),
-            winShmLockString(pFile->exclMask)));
- #endif
-   return rc;
+   return 0;
  }
  
  /*
- ** For connection p, unlock all of the locks identified by the unlockMask
- ** parameter.
+ ** Open a file.
  */
- static int winShmUnlock(
-   winShmFile *pFile,   /* The underlying shared-memory file */
-   winShm *p,           /* The connection to be unlocked */
-   u8 unlockMask         /* Mask of locks to be unlocked */
+ static int winOpen(
+   sqlite3_vfs *pVfs,        /* Not used */
+   const char *zName,        /* Name of the file (UTF-8) */
+   sqlite3_file *id,         /* Write the SQLite file handle here */
+   int flags,                /* Open mode flags */
+   int *pOutFlags            /* Status return flags */
  ){
-   int rc;      /* Result code */
-   winShm *pX; /* For looping over all sibling connections */
-   u8 allMask;  /* Union of locks held by connections other than "p" */
+   HANDLE h;
+   DWORD dwDesiredAccess;
+   DWORD dwShareMode;
+   DWORD dwCreationDisposition;
+   DWORD dwFlagsAndAttributes = 0;
+ #if SQLITE_OS_WINCE
+   int isTemp = 0;
+ #endif
+   winFile *pFile = (winFile*)id;
+   void *zConverted;                 /* Filename in OS encoding */
+   const char *zUtf8Name = zName;    /* Filename in UTF-8 encoding */
+   char zTmpname[MAX_PATH+1];        /* Buffer used to create temp filename */
  
-   /* Access to the winShmFile object is serialized by the caller */
-   assert( sqlite3_mutex_held(pFile->mutex) );
+   assert( id!=0 );
+   UNUSED_PARAMETER(pVfs);
  
-   /* don't attempt to unlock anything we don't have locks for */
-   if( (unlockMask & (p->exclMask|p->sharedMask)) != unlockMask ){
-     OSTRACE(("SHM-LOCK %d unlocking more than we have locked - requested %s - have %s\n",
-              pFile->hFile.h,
-              winShmLockString(unlockMask),
-              winShmLockString(p->exclMask|p->sharedMask)));
-     unlockMask &= (p->exclMask|p->sharedMask);
++  pFile->h = INVALID_HANDLE_VALUE;
++
+   /* If the second argument to this function is NULL, generate a 
+   ** temporary file name to use 
+   */
+   if( !zUtf8Name ){
+     int rc = getTempname(MAX_PATH+1, zTmpname);
+     if( rc!=SQLITE_OK ){
+       return rc;
+     }
+     zUtf8Name = zTmpname;
    }
  
-   /* Compute locks held by sibling connections */
-   allMask = 0;
-   for(pX=pFile->pFirst; pX; pX=pX->pNext){
-     if( pX==p ) continue;
-     assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
-     allMask |= pX->sharedMask;
+   /* Convert the filename to the system encoding. */
+   zConverted = convertUtf8Filename(zUtf8Name);
+   if( zConverted==0 ){
+     return SQLITE_NOMEM;
    }
  
-   /* Unlock the system-level locks */
-   if( (unlockMask & allMask)!=unlockMask ){
-     rc = winShmSystemLock(pFile, _SHM_UNLCK, unlockMask & ~allMask);
+   if( flags & SQLITE_OPEN_READWRITE ){
+     dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
    }else{
-     rc = SQLITE_OK;
+     dwDesiredAccess = GENERIC_READ;
    }
-   /* Undo the local locks */
-   if( rc==SQLITE_OK ){
-     p->exclMask &= ~unlockMask;
-     p->sharedMask &= ~unlockMask;
-   } 
-   return rc;
- }
- /*
- ** Get reader locks for connection p on all locks in the readMask parameter.
- */
- static int winShmSharedLock(
-   winShmFile *pFile,   /* The underlying shared-memory file */
-   winShm *p,           /* The connection to get the shared locks */
-   u8 readMask           /* Mask of shared locks to be acquired */
- ){
-   int rc;        /* Result code */
-   winShm *pX;   /* For looping over all sibling connections */
-   u8 allShared;  /* Union of locks held by connections other than "p" */
-   /* Access to the winShmFile object is serialized by the caller */
-   assert( sqlite3_mutex_held(pFile->mutex) );
-   /* Find out which shared locks are already held by sibling connections.
-   ** If any sibling already holds an exclusive lock, go ahead and return
-   ** SQLITE_BUSY.
+   /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is 
+   ** created. SQLite doesn't use it to indicate "exclusive access" 
+   ** as it is usually understood.
    */
-   allShared = 0;
-   for(pX=pFile->pFirst; pX; pX=pX->pNext){
-     if( pX==p ) continue;
-     if( (pX->exclMask & readMask)!=0 ) return SQLITE_BUSY;
-     allShared |= pX->sharedMask;
+   assert(!(flags & SQLITE_OPEN_EXCLUSIVE) || (flags & SQLITE_OPEN_CREATE));
+   if( flags & SQLITE_OPEN_EXCLUSIVE ){
+     /* Creates a new file, only if it does not already exist. */
+     /* If the file exists, it fails. */
+     dwCreationDisposition = CREATE_NEW;
+   }else if( flags & SQLITE_OPEN_CREATE ){
+     /* Open existing file, or create if it doesn't exist */
+     dwCreationDisposition = OPEN_ALWAYS;
+   }else{
+     /* Opens a file, only if it exists. */
+     dwCreationDisposition = OPEN_EXISTING;
    }
-   /* Get shared locks at the system level, if necessary */
-   if( (~allShared) & readMask ){
-     rc = winShmSystemLock(pFile, _SHM_RDLCK, readMask);
+   dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+   if( flags & SQLITE_OPEN_DELETEONCLOSE ){
+ #if SQLITE_OS_WINCE
+     dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN;
+     isTemp = 1;
+ #else
+     dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY
+                                | FILE_ATTRIBUTE_HIDDEN
+                                | FILE_FLAG_DELETE_ON_CLOSE;
+ #endif
    }else{
-     rc = SQLITE_OK;
+     dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
+   }
+   /* Reports from the internet are that performance is always
+   ** better if FILE_FLAG_RANDOM_ACCESS is used.  Ticket #2699. */
+ #if SQLITE_OS_WINCE
+   dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
+ #endif
+   if( isNT() ){
+     h = CreateFileW((WCHAR*)zConverted,
+        dwDesiredAccess,
+        dwShareMode,
+        NULL,
+        dwCreationDisposition,
+        dwFlagsAndAttributes,
+        NULL
+     );
+ /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
+ ** Since the ASCII version of these Windows API do not exist for WINCE,
+ ** it's important to not reference them for WINCE builds.
+ */
+ #if SQLITE_OS_WINCE==0
+   }else{
+     h = CreateFileA((char*)zConverted,
+        dwDesiredAccess,
+        dwShareMode,
+        NULL,
+        dwCreationDisposition,
+        dwFlagsAndAttributes,
+        NULL
+     );
+ #endif
+   }
++  OSTRACE(("OPEN %d %s 0x%lx %s\n", 
++           h, zName, dwDesiredAccess, 
++           h==INVALID_HANDLE_VALUE ? "failed" : "ok"));
+   if( h==INVALID_HANDLE_VALUE ){
+     free(zConverted);
+     if( flags & SQLITE_OPEN_READWRITE ){
+       return winOpen(pVfs, zName, id, 
+              ((flags|SQLITE_OPEN_READONLY)&~SQLITE_OPEN_READWRITE), pOutFlags);
+     }else{
+       return SQLITE_CANTOPEN_BKPT;
+     }
+   }
+   if( pOutFlags ){
+     if( flags & SQLITE_OPEN_READWRITE ){
+       *pOutFlags = SQLITE_OPEN_READWRITE;
+     }else{
+       *pOutFlags = SQLITE_OPEN_READONLY;
+     }
+   }
+   memset(pFile, 0, sizeof(*pFile));
+   pFile->pMethod = &winIoMethod;
+   pFile->h = h;
+   pFile->lastErrno = NO_ERROR;
++  pFile->pVfs = pVfs;
++  pFile->pShm = 0;
++  pFile->zPath = zName;
+   pFile->sectorSize = getSectorSize(pVfs, zUtf8Name);
+ #if SQLITE_OS_WINCE
+   if( (flags & (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)) ==
+                (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)
+        && !winceCreateLock(zName, pFile)
+   ){
+     CloseHandle(h);
+     free(zConverted);
+     return SQLITE_CANTOPEN_BKPT;
    }
-   /* Get the local shared locks */
-   if( rc==SQLITE_OK ){
-     p->sharedMask |= readMask;
+   if( isTemp ){
+     pFile->zDeleteOnClose = zConverted;
+   }else
+ #endif
+   {
+     free(zConverted);
    }
-   return rc;
+   OpenCounter(+1);
+   return SQLITE_OK;
  }
  
  /*
- ** For connection p, get an exclusive lock on all locks identified in
- ** the writeMask parameter.
+ ** Delete the named file.
+ **
+ ** Note that windows does not allow a file to be deleted if some other
+ ** process has it open.  Sometimes a virus scanner or indexing program
+ ** will open a journal file shortly after it is created in order to do
+ ** whatever it does.  While this other process is holding the
+ ** file open, we will be unable to delete it.  To work around this
+ ** problem, we delay 100 milliseconds and try to delete again.  Up
+ ** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
+ ** up and returning an error.
  */
- static int winShmExclusiveLock(
-   winShmFile *pFile,    /* The underlying shared-memory file */
-   winShm *p,            /* The connection to get the exclusive locks */
-   u8 writeMask           /* Mask of exclusive locks to be acquired */
+ #define MX_DELETION_ATTEMPTS 5
+ static int winDelete(
+   sqlite3_vfs *pVfs,          /* Not used on win32 */
+   const char *zFilename,      /* Name of file to delete */
+   int syncDir                 /* Not used on win32 */
  ){
-   int rc;        /* Result code */
-   winShm *pX;   /* For looping over all sibling connections */
-   /* Access to the winShmFile object is serialized by the caller */
-   assert( sqlite3_mutex_held(pFile->mutex) );
-   /* Make sure no sibling connections hold locks that will block this
-   ** lock.  If any do, return SQLITE_BUSY right away.
-   */
-   for(pX=pFile->pFirst; pX; pX=pX->pNext){
-     if( pX==p ) continue;
-     if( (pX->exclMask & writeMask)!=0 ) return SQLITE_BUSY;
-     if( (pX->sharedMask & writeMask)!=0 ) return SQLITE_BUSY;
+   int cnt = 0;
+   DWORD rc;
+   DWORD error = 0;
+   void *zConverted = convertUtf8Filename(zFilename);
+   UNUSED_PARAMETER(pVfs);
+   UNUSED_PARAMETER(syncDir);
+   if( zConverted==0 ){
+     return SQLITE_NOMEM;
    }
-   /* Get the exclusive locks at the system level.  Then if successful
-   ** also mark the local connection as being locked.
-   */
-   rc = winShmSystemLock(pFile, _SHM_WRLCK, writeMask);
-   if( rc==SQLITE_OK ){
-     p->sharedMask &= ~writeMask;
-     p->exclMask |= writeMask;
+   SimulateIOError(return SQLITE_IOERR_DELETE);
+   if( isNT() ){
+     do{
+       DeleteFileW(zConverted);
+     }while(   (   ((rc = GetFileAttributesW(zConverted)) != INVALID_FILE_ATTRIBUTES)
+                || ((error = GetLastError()) == ERROR_ACCESS_DENIED))
+            && (++cnt < MX_DELETION_ATTEMPTS)
+            && (Sleep(100), 1) );
+ /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
+ ** Since the ASCII version of these Windows API do not exist for WINCE,
+ ** it's important to not reference them for WINCE builds.
+ */
+ #if SQLITE_OS_WINCE==0
+   }else{
+     do{
+       DeleteFileA(zConverted);
+     }while(   (   ((rc = GetFileAttributesA(zConverted)) != INVALID_FILE_ATTRIBUTES)
+                || ((error = GetLastError()) == ERROR_ACCESS_DENIED))
+            && (++cnt < MX_DELETION_ATTEMPTS)
+            && (Sleep(100), 1) );
+ #endif
    }
-   return rc;
+   free(zConverted);
 -  OSTRACE(("DELETE \"%s\"\n", zFilename));
++  OSTRACE(("DELETE \"%s\" %s\n", zFilename,
++       ( (rc==INVALID_FILE_ATTRIBUTES) && (error==ERROR_FILE_NOT_FOUND)) ?
++         "ok" : "failed" ));
++ 
+   return (   (rc == INVALID_FILE_ATTRIBUTES) 
+           && (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK : SQLITE_IOERR_DELETE;
  }
  
  /*
@@@ -2676,192 -1795,124 +2758,137 @@@ static int winSleep(sqlite3_vfs *pVfs, 
  }
  
  /*
- ** Symbolic names for LOCK states used for debugging.
 -** The following variable, if set to a non-zero value, becomes the result
 -** returned from sqlite3OsCurrentTime().  This is used for testing.
++** The following variable, if set to a non-zero value, is interpreted as
++** the number of seconds since 1970 and is used to set the result of
++** sqlite3OsCurrentTime() during testing.
  */
- #ifdef SQLITE_DEBUG
- static const char *azLkName[] = {
-   "UNLOCK",
-   "READ",
-   "READ_FULL",
-   "WRITE",
-   "PENDING",
-   "CHECKPOINT",
-   "RECOVER"
- };
+ #ifdef SQLITE_TEST
 -int sqlite3_current_time = 0;
++int sqlite3_current_time = 0;  /* Fake system time in seconds since 1970. */
  #endif
  
  /*
- ** Change the lock state for a shared-memory segment.
 -** Find the current time (in Universal Coordinated Time).  Write the
 -** current time and date as a Julian Day number into *prNow and
 -** return 0.  Return 1 if the time and date cannot be found.
++** Find the current time (in Universal Coordinated Time).  Write into *piNow
++** the current time and date as a Julian Day number times 86_400_000.  In
++** other words, write into *piNow the number of milliseconds since the Julian
++** epoch of noon in Greenwich on November 24, 4714 B.C according to the
++** proleptic Gregorian calendar.
++**
++** On success, return 0.  Return 1 if the time and date cannot be found.
  */
- static int winShmLock(
-   sqlite3_vfs *pVfs,         /* The VFS */
-   sqlite3_shm *pSharedMem,   /* Pointer from winShmOpen() */
-   int desiredLock,           /* One of SQLITE_SHM_xxxxx locking states */
-   int *pGotLock              /* The lock you actually got */
- ){
-   winShm *p = (winShm*)pSharedMem;
-   winShmFile *pFile = p->pFile;
-   int rc = SQLITE_PROTOCOL;
-   UNUSED_PARAMETER(pVfs);
-   /* Note that SQLITE_SHM_READ_FULL and SQLITE_SHM_PENDING are never
-   ** directly requested; they are side effects from requesting
-   ** SQLITE_SHM_READ and SQLITE_SHM_CHECKPOINT, respectively.
 -int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
 -  FILETIME ft;
++static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
+   /* FILETIME structure is a 64-bit value representing the number of 
+      100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). 
    */
-   assert( desiredLock==SQLITE_SHM_UNLOCK
-        || desiredLock==SQLITE_SHM_READ
-        || desiredLock==SQLITE_SHM_WRITE
-        || desiredLock==SQLITE_SHM_CHECKPOINT
-        || desiredLock==SQLITE_SHM_RECOVER );
 -  sqlite3_int64 timeW;   /* Whole days */
 -  sqlite3_int64 timeF;   /* Fractional Days */
 -
 -  /* Number of 100-nanosecond intervals in a single day */
 -  static const sqlite3_int64 ntuPerDay = 
 -      10000000*(sqlite3_int64)86400;
 -
 -  /* Number of 100-nanosecond intervals in half of a day */
 -  static const sqlite3_int64 ntuPerHalfDay = 
 -      10000000*(sqlite3_int64)43200;
 -
++  FILETIME ft;
++  static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000;
++#ifdef SQLITE_TEST
++  static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
++#endif
+   /* 2^32 - to avoid use of LL and warnings in gcc */
+   static const sqlite3_int64 max32BitValue = 
+       (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + (sqlite3_int64)294967296;
  
-   /* Return directly if this is just a lock state query, or if
-   ** the connection is already in the desired locking state.
-   */
-   if( desiredLock==p->lockState
-    || (desiredLock==SQLITE_SHM_READ && p->lockState==SQLITE_SHM_READ_FULL)
-   ){
-     OSTRACE(("SHM-LOCK %d shmid-%d, pid-%d request %s and got %s\n",
-              pFile->hFile.h,
-              p->id, (int)GetCurrentProcessId(), azLkName[desiredLock], azLkName[p->lockState]));
-     if( pGotLock ) *pGotLock = p->lockState;
-     return SQLITE_OK;
+ #if SQLITE_OS_WINCE
+   SYSTEMTIME time;
+   GetSystemTime(&time);
+   /* if SystemTimeToFileTime() fails, it returns zero. */
+   if (!SystemTimeToFileTime(&time,&ft)){
+     return 1;
    }
 -  UNUSED_PARAMETER(pVfs);
 -  timeW = (((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) + (sqlite3_int64)ft.dwLowDateTime;
 -  timeF = timeW % ntuPerDay;          /* fractional days (100-nanoseconds) */
 -  timeW = timeW / ntuPerDay;          /* whole days */
 -  timeW = timeW + 2305813;            /* add whole days (from 2305813.5) */
 -  timeF = timeF + ntuPerHalfDay;      /* add half a day (from 2305813.5) */
 -  timeW = timeW + (timeF/ntuPerDay);  /* add whole day if half day made one */
 -  timeF = timeF % ntuPerDay;          /* compute new fractional days */
 -  *prNow = (double)timeW + ((double)timeF / (double)ntuPerDay);
+ #else
+   GetSystemTimeAsFileTime( &ft );
+ #endif
-   OSTRACE(("SHM-LOCK %d shmid-%d, pid-%d request %s->%s\n",
-            pFile->hFile.h,
-            p->id, (int)GetCurrentProcessId(), azLkName[p->lockState], azLkName[desiredLock]));
-   
-   if( desiredLock==SQLITE_SHM_RECOVER && !p->hasMutexBuf ){
-     assert( sqlite3_mutex_notheld(pFile->mutex) );
-     sqlite3_mutex_enter(pFile->mutexBuf);
-     p->hasMutexBuf = 1;
 +
 -    *prNow = ((double)sqlite3_current_time + (double)43200) / (double)86400 + (double)2440587;
++  *piNow = winFiletimeEpoch +
++            ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) + 
++               (sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)1000;
++
+ #ifdef SQLITE_TEST
+   if( sqlite3_current_time ){
++    *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
    }
-   sqlite3_mutex_enter(pFile->mutex);
-   switch( desiredLock ){
-     case SQLITE_SHM_UNLOCK: {
-       assert( p->lockState!=SQLITE_SHM_RECOVER );
-       winShmUnlock(pFile, p, WIN_SHM_A|WIN_SHM_B|WIN_SHM_C|WIN_SHM_D);
-       rc = SQLITE_OK;
-       p->lockState = SQLITE_SHM_UNLOCK;
-       break;
-     }
-     case SQLITE_SHM_READ: {
-       if( p->lockState==SQLITE_SHM_UNLOCK ){
-         int nAttempt;
-         rc = SQLITE_BUSY;
-         assert( p->lockState==SQLITE_SHM_UNLOCK );
-         for(nAttempt=0; nAttempt<5 && rc==SQLITE_BUSY; nAttempt++){
-           rc = winShmSharedLock(pFile, p, WIN_SHM_A|WIN_SHM_B);
-           if( rc==SQLITE_BUSY ){
-             rc = winShmSharedLock(pFile, p, WIN_SHM_D);
-             if( rc==SQLITE_OK ){
-               p->lockState = SQLITE_SHM_READ_FULL;
-             }
-           }else{
-             winShmUnlock(pFile, p, WIN_SHM_B);
-             p->lockState = SQLITE_SHM_READ;
-           }
-         }
-       }else{
-        assert( p->lockState==SQLITE_SHM_WRITE
-                || p->lockState==SQLITE_SHM_RECOVER );
-         rc = winShmSharedLock(pFile, p, WIN_SHM_A);
-         winShmUnlock(pFile, p, WIN_SHM_C|WIN_SHM_D);
-         p->lockState = SQLITE_SHM_READ;
-       }
-       break;
-     }
-     case SQLITE_SHM_WRITE: {
-       assert( p->lockState==SQLITE_SHM_READ 
-               || p->lockState==SQLITE_SHM_READ_FULL );
-       rc = winShmExclusiveLock(pFile, p, WIN_SHM_C|WIN_SHM_D);
-       if( rc==SQLITE_OK ){
-         p->lockState = SQLITE_SHM_WRITE;
-       }
-       break;
-     }
-     case SQLITE_SHM_CHECKPOINT: {
-       assert( p->lockState==SQLITE_SHM_UNLOCK
-            || p->lockState==SQLITE_SHM_PENDING
-       );
-       if( p->lockState==SQLITE_SHM_UNLOCK ){
-         rc = winShmExclusiveLock(pFile, p, WIN_SHM_B|WIN_SHM_C);
-         if( rc==SQLITE_OK ){
-           p->lockState = SQLITE_SHM_PENDING;
-         }
-       }
-       if( p->lockState==SQLITE_SHM_PENDING ){
-         rc = winShmExclusiveLock(pFile, p, WIN_SHM_A);
-         if( rc==SQLITE_OK ){
-           p->lockState = SQLITE_SHM_CHECKPOINT;
-         }
-       }
-       break;
-     }
-     default: {
-       assert( desiredLock==SQLITE_SHM_RECOVER );
-       assert( p->lockState==SQLITE_SHM_READ
-            || p->lockState==SQLITE_SHM_READ_FULL
-       );
-       assert( sqlite3_mutex_held(pFile->mutexBuf) );
-       rc = winShmExclusiveLock(pFile, p, WIN_SHM_C);
-       if( rc==SQLITE_OK ){
-         p->lockState = SQLITE_SHM_RECOVER;
-       }
-       break;
-     }
+ #endif
++  UNUSED_PARAMETER(pVfs);
+   return 0;
+ }
++/*
++** Find the current time (in Universal Coordinated Time).  Write the
++** current time and date as a Julian Day number into *prNow and
++** return 0.  Return 1 if the time and date cannot be found.
++*/
++int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
++  int rc;
++  sqlite3_int64 i;
++  rc = winCurrentTimeInt64(pVfs, &i);
++  if( !rc ){
++    *prNow = i/86400000.0;
 +  }
-   sqlite3_mutex_leave(pFile->mutex);
-   OSTRACE(("SHM-LOCK %d shmid-%d, pid-%d got %s\n",
-            pFile->hFile.h, 
-            p->id, (int)GetCurrentProcessId(), azLkName[p->lockState]));
-   if( pGotLock ) *pGotLock = p->lockState;
 +  return rc;
 +}
 +
- #else
- # define winShmOpen    0
- # define winShmSize    0
- # define winShmGet     0
- # define winShmRelease 0
- # define winShmLock    0
- # define winShmClose   0
- #endif /* #ifndef SQLITE_OMIT_WAL */
+ /*
+ ** The idea is that this function works like a combination of
+ ** GetLastError() and FormatMessage() on windows (or errno and
+ ** strerror_r() on unix). After an error is returned by an OS
+ ** function, SQLite calls this function with zBuf pointing to
+ ** a buffer of nBuf bytes. The OS layer should populate the
+ ** buffer with a nul-terminated UTF-8 encoded error message
+ ** describing the last IO error to have occurred within the calling
+ ** thread.
+ **
+ ** If the error message is too large for the supplied buffer,
+ ** it should be truncated. The return value of xGetLastError
+ ** is zero if the error message fits in the buffer, or non-zero
+ ** otherwise (if the message was truncated). If non-zero is returned,
+ ** then it is not necessary to include the nul-terminator character
+ ** in the output buffer.
+ **
+ ** Not supplying an error message will have no adverse effect
+ ** on SQLite. It is fine to have an implementation that never
+ ** returns an error message:
+ **
+ **   int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
+ **     assert(zBuf[0]=='\0');
+ **     return 0;
+ **   }
+ **
+ ** However if an error message is supplied, it will be incorporated
+ ** by sqlite into the error message available to the user using
+ ** sqlite3_errmsg(), possibly making IO errors easier to debug.
+ */
+ static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
+   UNUSED_PARAMETER(pVfs);
+   return getLastErrorMsg(nBuf, zBuf);
+ }
 +
 +
  /*
  ** Initialize and deinitialize the operating system interface.
  */
  int sqlite3_os_init(void){
    static sqlite3_vfs winVfs = {
 -    1,                 /* iVersion */
 -    sizeof(winFile),   /* szOsFile */
 -    MAX_PATH,          /* mxPathname */
 -    0,                 /* pNext */
 -    "win32",           /* zName */
 -    0,                 /* pAppData */
 - 
 -    winOpen,           /* xOpen */
 -    winDelete,         /* xDelete */
 -    winAccess,         /* xAccess */
 -    winFullPathname,   /* xFullPathname */
 -    winDlOpen,         /* xDlOpen */
 -    winDlError,        /* xDlError */
 -    winDlSym,          /* xDlSym */
 -    winDlClose,        /* xDlClose */
 -    winRandomness,     /* xRandomness */
 -    winSleep,          /* xSleep */
 -    winCurrentTime,    /* xCurrentTime */
 -    winGetLastError,   /* xGetLastError */
 +    2,                   /* iVersion */
 +    sizeof(winFile),     /* szOsFile */
 +    MAX_PATH,            /* mxPathname */
 +    0,                   /* pNext */
 +    "win32",             /* zName */
 +    0,                   /* pAppData */
 +    winOpen,             /* xOpen */
 +    winDelete,           /* xDelete */
 +    winAccess,           /* xAccess */
 +    winFullPathname,     /* xFullPathname */
 +    winDlOpen,           /* xDlOpen */
 +    winDlError,          /* xDlError */
 +    winDlSym,            /* xDlSym */
 +    winDlClose,          /* xDlClose */
 +    winRandomness,       /* xRandomness */
 +    winSleep,            /* xSleep */
 +    winCurrentTime,      /* xCurrentTime */
 +    winGetLastError,     /* xGetLastError */
-     winShmOpen,          /* xShmOpen */
-     winShmSize,          /* xShmSize */
-     winShmGet,           /* xShmGet */
-     winShmRelease,       /* xShmRelease */
-     winShmLock,          /* xShmLock */
-     winShmClose,         /* xShmClose */
 +    0,                   /* xRename */
 +    winCurrentTimeInt64, /* xCurrentTimeInt64 */
    };
  
    sqlite3_vfs_register(&winVfs, 1);