xref: /sqlite-3.40.0/src/os_win.c (revision 6ca514b0)
1bbd42a6dSdrh /*
2bbd42a6dSdrh ** 2004 May 22
3bbd42a6dSdrh **
4bbd42a6dSdrh ** The author disclaims copyright to this source code.  In place of
5bbd42a6dSdrh ** a legal notice, here is a blessing:
6bbd42a6dSdrh **
7bbd42a6dSdrh **    May you do good and not evil.
8bbd42a6dSdrh **    May you find forgiveness for yourself and forgive others.
9bbd42a6dSdrh **    May you share freely, never taking more than you give.
10bbd42a6dSdrh **
11bbd42a6dSdrh ******************************************************************************
12bbd42a6dSdrh **
13318507b7Smistachkin ** This file contains code that is specific to Windows.
14bbd42a6dSdrh */
15bbd42a6dSdrh #include "sqliteInt.h"
16318507b7Smistachkin #if SQLITE_OS_WIN               /* This file is used for Windows only */
17bbd42a6dSdrh 
1809bf0e8dSdrh #ifdef __CYGWIN__
1909bf0e8dSdrh # include <sys/cygwin.h>
2009bf0e8dSdrh #endif
2109bf0e8dSdrh 
22bbd42a6dSdrh /*
23bbd42a6dSdrh ** Include code that is common to all os_*.c files
24bbd42a6dSdrh */
25bbd42a6dSdrh #include "os_common.h"
26bbd42a6dSdrh 
27bbd42a6dSdrh /*
28318507b7Smistachkin ** Some Microsoft compilers lack this definition.
29171fa295Sshane */
30171fa295Sshane #ifndef INVALID_FILE_ATTRIBUTES
31171fa295Sshane # define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
32171fa295Sshane #endif
33171fa295Sshane 
3483235214Sdrh /* Forward references */
3583235214Sdrh typedef struct winShm winShm;           /* A connection to shared-memory */
3683235214Sdrh typedef struct winShmNode winShmNode;   /* A region of shared-memory */
3783235214Sdrh 
38cc78fea4Sdrh /*
3972aead81Sdrh ** WinCE lacks native support for file locking so we have to fake it
4072aead81Sdrh ** with some code of our own.
4172aead81Sdrh */
4229bafeabSdanielk1977 #if SQLITE_OS_WINCE
4372aead81Sdrh typedef struct winceLock {
4472aead81Sdrh   int nReaders;       /* Number of reader locks obtained */
4572aead81Sdrh   BOOL bPending;      /* Indicates a pending lock has been obtained */
4672aead81Sdrh   BOOL bReserved;     /* Indicates a reserved lock has been obtained */
4772aead81Sdrh   BOOL bExclusive;    /* Indicates an exclusive lock has been obtained */
4872aead81Sdrh } winceLock;
4972aead81Sdrh #endif
5072aead81Sdrh 
5172aead81Sdrh /*
52153c62c4Sdrh ** The winFile structure is a subclass of sqlite3_file* specific to the win32
53054889ecSdrh ** portability layer.
549cbe6352Sdrh */
55054889ecSdrh typedef struct winFile winFile;
56054889ecSdrh struct winFile {
5783235214Sdrh   const sqlite3_io_methods *pMethod; /*** Must be first ***/
5883235214Sdrh   sqlite3_vfs *pVfs;      /* The VFS used to open this file */
599cbe6352Sdrh   HANDLE h;               /* Handle for accessing the file */
60f0b190d9Sdrh   u8 locktype;            /* Type of lock currently held on this file */
619cbe6352Sdrh   short sharedLockByte;   /* Randomly chosen byte used as a shared lock */
62f0b190d9Sdrh   u8 bPersistWal;         /* True to persist WAL files */
639db299fbSshane   DWORD lastErrno;        /* The Windows errno from the last I/O error */
6450daafc7Sshane   DWORD sectorSize;       /* Sector size of the device file is on */
6583235214Sdrh   winShm *pShm;           /* Instance of shared memory on this file */
6683235214Sdrh   const char *zPath;      /* Full pathname of this file */
67502019c8Sdan   int szChunk;            /* Chunk size configured by FCNTL_CHUNK_SIZE */
6829bafeabSdanielk1977 #if SQLITE_OS_WINCE
69318507b7Smistachkin   LPWSTR zDeleteOnClose;  /* Name of file to delete when closing */
7072aead81Sdrh   HANDLE hMutex;          /* Mutex used to control access to shared lock */
7172aead81Sdrh   HANDLE hShared;         /* Shared memory segment used for locking */
7272aead81Sdrh   winceLock local;        /* Locks obtained by this instance of winFile */
7372aead81Sdrh   winceLock *shared;      /* Global shared lock memory for the file  */
74cc78fea4Sdrh #endif
759cbe6352Sdrh };
769cbe6352Sdrh 
771b186a99Smistachkin /*
781b186a99Smistachkin  * If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the
791b186a99Smistachkin  * various Win32 API heap functions instead of our own.
801b186a99Smistachkin  */
811b186a99Smistachkin #ifdef SQLITE_WIN32_MALLOC
821b186a99Smistachkin /*
831b186a99Smistachkin  * The initial size of the Win32-specific heap.  This value may be zero.
841b186a99Smistachkin  */
851b186a99Smistachkin #ifndef SQLITE_WIN32_HEAP_INIT_SIZE
861b186a99Smistachkin #  define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_DEFAULT_CACHE_SIZE) * \
871b186a99Smistachkin                                        (SQLITE_DEFAULT_PAGE_SIZE) + 4194304)
881b186a99Smistachkin #endif
891b186a99Smistachkin 
901b186a99Smistachkin /*
911b186a99Smistachkin  * The maximum size of the Win32-specific heap.  This value may be zero.
921b186a99Smistachkin  */
931b186a99Smistachkin #ifndef SQLITE_WIN32_HEAP_MAX_SIZE
941b186a99Smistachkin #  define SQLITE_WIN32_HEAP_MAX_SIZE  (0)
951b186a99Smistachkin #endif
961b186a99Smistachkin 
971b186a99Smistachkin /*
98155892ccSmistachkin  * The extra flags to use in calls to the Win32 heap APIs.  This value may be
99155892ccSmistachkin  * zero for the default behavior.
100155892ccSmistachkin  */
101155892ccSmistachkin #ifndef SQLITE_WIN32_HEAP_FLAGS
102155892ccSmistachkin #  define SQLITE_WIN32_HEAP_FLAGS     (0)
103155892ccSmistachkin #endif
104155892ccSmistachkin 
105155892ccSmistachkin /*
1061b186a99Smistachkin ** The winMemData structure stores information required by the Win32-specific
1071b186a99Smistachkin ** sqlite3_mem_methods implementation.
1081b186a99Smistachkin */
1091b186a99Smistachkin typedef struct winMemData winMemData;
1101b186a99Smistachkin struct winMemData {
1117da32b58Smistachkin #ifndef NDEBUG
1121b186a99Smistachkin   u32 magic;    /* Magic number to detect structure corruption. */
1137da32b58Smistachkin #endif
1141b186a99Smistachkin   HANDLE hHeap; /* The handle to our heap. */
1151b186a99Smistachkin   BOOL bOwned;  /* Do we own the heap (i.e. destroy it on shutdown)? */
1161b186a99Smistachkin };
1171b186a99Smistachkin 
1187da32b58Smistachkin #ifndef NDEBUG
1191b186a99Smistachkin #define WINMEM_MAGIC     0x42b2830b
1207da32b58Smistachkin #endif
1211b186a99Smistachkin 
1227da32b58Smistachkin static struct winMemData win_mem_data = {
1237da32b58Smistachkin #ifndef NDEBUG
1247da32b58Smistachkin   WINMEM_MAGIC,
1257da32b58Smistachkin #endif
1267da32b58Smistachkin   NULL, FALSE
1277da32b58Smistachkin };
1281b186a99Smistachkin 
1297da32b58Smistachkin #ifndef NDEBUG
130468690efSmistachkin #define winMemAssertMagic() assert( win_mem_data.magic==WINMEM_MAGIC )
1317da32b58Smistachkin #else
1327da32b58Smistachkin #define winMemAssertMagic()
1337da32b58Smistachkin #endif
1347da32b58Smistachkin 
135468690efSmistachkin #define winMemGetHeap() win_mem_data.hHeap
136468690efSmistachkin 
1371b186a99Smistachkin static void *winMemMalloc(int nBytes);
1381b186a99Smistachkin static void winMemFree(void *pPrior);
1391b186a99Smistachkin static void *winMemRealloc(void *pPrior, int nBytes);
1401b186a99Smistachkin static int winMemSize(void *p);
1411b186a99Smistachkin static int winMemRoundup(int n);
1421b186a99Smistachkin static int winMemInit(void *pAppData);
1431b186a99Smistachkin static void winMemShutdown(void *pAppData);
1441b186a99Smistachkin 
1451b186a99Smistachkin const sqlite3_mem_methods *sqlite3MemGetWin32(void);
1461b186a99Smistachkin #endif /* SQLITE_WIN32_MALLOC */
14750990dbbSdrh 
14850daafc7Sshane /*
14950daafc7Sshane ** Forward prototypes.
15050daafc7Sshane */
15150daafc7Sshane static int getSectorSize(
15250daafc7Sshane     sqlite3_vfs *pVfs,
15350daafc7Sshane     const char *zRelative     /* UTF-8 file name */
15450daafc7Sshane );
1559cbe6352Sdrh 
1569cbe6352Sdrh /*
157c0929987Sdrh ** The following variable is (normally) set once and never changes
1586c3c1a09Smistachkin ** thereafter.  It records whether the operating system is Win9x
159c0929987Sdrh ** or WinNT.
160c0929987Sdrh **
161c0929987Sdrh ** 0:   Operating system unknown.
1626c3c1a09Smistachkin ** 1:   Operating system is Win9x.
163c0929987Sdrh ** 2:   Operating system is WinNT.
164c0929987Sdrh **
165c0929987Sdrh ** In order to facilitate testing on a WinNT system, the test fixture
166c0929987Sdrh ** can manually set this value to 1 to emulate Win98 behavior.
167c0929987Sdrh */
168153c62c4Sdrh #ifdef SQLITE_TEST
169c0929987Sdrh int sqlite3_os_type = 0;
170153c62c4Sdrh #else
171153c62c4Sdrh static int sqlite3_os_type = 0;
172153c62c4Sdrh #endif
173c0929987Sdrh 
174c0929987Sdrh /*
175318507b7Smistachkin ** Many system calls are accessed through pointer-to-functions so that
176318507b7Smistachkin ** they may be overridden at runtime to facilitate fault injection during
177318507b7Smistachkin ** testing and sandboxing.  The following array holds the names and pointers
178318507b7Smistachkin ** to all overrideable system calls.
179318507b7Smistachkin */
180318507b7Smistachkin #if !SQLITE_OS_WINCE
181318507b7Smistachkin #  define SQLITE_WIN32_HAS_ANSI
182318507b7Smistachkin #endif
183318507b7Smistachkin 
184c4eef45cSmistachkin #if SQLITE_OS_WINCE || SQLITE_OS_WINNT
185318507b7Smistachkin #  define SQLITE_WIN32_HAS_WIDE
186318507b7Smistachkin #endif
187318507b7Smistachkin 
188318507b7Smistachkin #ifndef SYSCALL
189318507b7Smistachkin #  define SYSCALL sqlite3_syscall_ptr
190318507b7Smistachkin #endif
191318507b7Smistachkin 
192318507b7Smistachkin #if SQLITE_OS_WINCE
193318507b7Smistachkin /*
194318507b7Smistachkin ** These macros are necessary because Windows CE does not natively support the
195318507b7Smistachkin ** Win32 APIs LockFile, UnlockFile, and LockFileEx.
196318507b7Smistachkin  */
197318507b7Smistachkin 
198318507b7Smistachkin #  define LockFile(a,b,c,d,e)       winceLockFile(&a, b, c, d, e)
199318507b7Smistachkin #  define UnlockFile(a,b,c,d,e)     winceUnlockFile(&a, b, c, d, e)
200318507b7Smistachkin #  define LockFileEx(a,b,c,d,e,f)   winceLockFileEx(&a, b, c, d, e, f)
201318507b7Smistachkin 
202318507b7Smistachkin /*
203318507b7Smistachkin ** These are the special syscall hacks for Windows CE.  The locking related
204318507b7Smistachkin ** defines here refer to the macros defined just above.
205318507b7Smistachkin  */
206318507b7Smistachkin 
207318507b7Smistachkin #  define osAreFileApisANSI()       1
208318507b7Smistachkin #  define osLockFile                LockFile
209318507b7Smistachkin #  define osUnlockFile              UnlockFile
210318507b7Smistachkin #  define osLockFileEx              LockFileEx
211318507b7Smistachkin #endif
212318507b7Smistachkin 
213318507b7Smistachkin static struct win_syscall {
214318507b7Smistachkin   const char *zName;            /* Name of the sytem call */
215318507b7Smistachkin   sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
216318507b7Smistachkin   sqlite3_syscall_ptr pDefault; /* Default value */
217318507b7Smistachkin } aSyscall[] = {
218318507b7Smistachkin #if !SQLITE_OS_WINCE
219318507b7Smistachkin   { "AreFileApisANSI",         (SYSCALL)AreFileApisANSI,         0 },
220318507b7Smistachkin 
221318507b7Smistachkin #define osAreFileApisANSI ((BOOL(WINAPI*)(VOID))aSyscall[0].pCurrent)
222318507b7Smistachkin #else
223318507b7Smistachkin   { "AreFileApisANSI",         (SYSCALL)0,                       0 },
224318507b7Smistachkin #endif
225318507b7Smistachkin 
226318507b7Smistachkin #if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
227318507b7Smistachkin   { "CharLowerW",              (SYSCALL)CharLowerW,              0 },
228318507b7Smistachkin #else
229318507b7Smistachkin   { "CharLowerW",              (SYSCALL)0,                       0 },
230318507b7Smistachkin #endif
231318507b7Smistachkin 
232318507b7Smistachkin #define osCharLowerW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[1].pCurrent)
233318507b7Smistachkin 
234318507b7Smistachkin #if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
235318507b7Smistachkin   { "CharUpperW",              (SYSCALL)CharUpperW,              0 },
236318507b7Smistachkin #else
237318507b7Smistachkin   { "CharUpperW",              (SYSCALL)0,                       0 },
238318507b7Smistachkin #endif
239318507b7Smistachkin 
240318507b7Smistachkin #define osCharUpperW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[2].pCurrent)
241318507b7Smistachkin 
242318507b7Smistachkin   { "CloseHandle",             (SYSCALL)CloseHandle,             0 },
243318507b7Smistachkin 
244318507b7Smistachkin #define osCloseHandle ((BOOL(WINAPI*)(HANDLE))aSyscall[3].pCurrent)
245318507b7Smistachkin 
246318507b7Smistachkin #if defined(SQLITE_WIN32_HAS_ANSI)
247318507b7Smistachkin   { "CreateFileA",             (SYSCALL)CreateFileA,             0 },
248318507b7Smistachkin #else
249318507b7Smistachkin   { "CreateFileA",             (SYSCALL)0,                       0 },
250318507b7Smistachkin #endif
251318507b7Smistachkin 
252318507b7Smistachkin #define osCreateFileA ((HANDLE(WINAPI*)(LPCSTR,DWORD,DWORD, \
253318507b7Smistachkin         LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[4].pCurrent)
254318507b7Smistachkin 
255318507b7Smistachkin #if defined(SQLITE_WIN32_HAS_WIDE)
256318507b7Smistachkin   { "CreateFileW",             (SYSCALL)CreateFileW,             0 },
257318507b7Smistachkin #else
258318507b7Smistachkin   { "CreateFileW",             (SYSCALL)0,                       0 },
259318507b7Smistachkin #endif
260318507b7Smistachkin 
261318507b7Smistachkin #define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \
262318507b7Smistachkin         LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent)
263318507b7Smistachkin 
264318507b7Smistachkin   { "CreateFileMapping",       (SYSCALL)CreateFileMapping,       0 },
265318507b7Smistachkin 
266318507b7Smistachkin #define osCreateFileMapping ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
267318507b7Smistachkin         DWORD,DWORD,DWORD,LPCTSTR))aSyscall[6].pCurrent)
268318507b7Smistachkin 
269318507b7Smistachkin #if defined(SQLITE_WIN32_HAS_WIDE)
270318507b7Smistachkin   { "CreateFileMappingW",      (SYSCALL)CreateFileMappingW,      0 },
271318507b7Smistachkin #else
272318507b7Smistachkin   { "CreateFileMappingW",      (SYSCALL)0,                       0 },
273318507b7Smistachkin #endif
274318507b7Smistachkin 
275318507b7Smistachkin #define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
276318507b7Smistachkin         DWORD,DWORD,DWORD,LPCWSTR))aSyscall[7].pCurrent)
277318507b7Smistachkin 
278318507b7Smistachkin #if defined(SQLITE_WIN32_HAS_WIDE)
279318507b7Smistachkin   { "CreateMutexW",            (SYSCALL)CreateMutexW,            0 },
280318507b7Smistachkin #else
281318507b7Smistachkin   { "CreateMutexW",            (SYSCALL)0,                       0 },
282318507b7Smistachkin #endif
283318507b7Smistachkin 
284318507b7Smistachkin #define osCreateMutexW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,BOOL, \
285318507b7Smistachkin         LPCWSTR))aSyscall[8].pCurrent)
286318507b7Smistachkin 
287318507b7Smistachkin #if defined(SQLITE_WIN32_HAS_ANSI)
288318507b7Smistachkin   { "DeleteFileA",             (SYSCALL)DeleteFileA,             0 },
289318507b7Smistachkin #else
290318507b7Smistachkin   { "DeleteFileA",             (SYSCALL)0,                       0 },
291318507b7Smistachkin #endif
292318507b7Smistachkin 
293318507b7Smistachkin #define osDeleteFileA ((BOOL(WINAPI*)(LPCSTR))aSyscall[9].pCurrent)
294318507b7Smistachkin 
295318507b7Smistachkin #if defined(SQLITE_WIN32_HAS_WIDE)
296318507b7Smistachkin   { "DeleteFileW",             (SYSCALL)DeleteFileW,             0 },
297318507b7Smistachkin #else
298318507b7Smistachkin   { "DeleteFileW",             (SYSCALL)0,                       0 },
299318507b7Smistachkin #endif
300318507b7Smistachkin 
301318507b7Smistachkin #define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[10].pCurrent)
302318507b7Smistachkin 
303318507b7Smistachkin #if SQLITE_OS_WINCE
304318507b7Smistachkin   { "FileTimeToLocalFileTime", (SYSCALL)FileTimeToLocalFileTime, 0 },
305318507b7Smistachkin #else
306318507b7Smistachkin   { "FileTimeToLocalFileTime", (SYSCALL)0,                       0 },
307318507b7Smistachkin #endif
308318507b7Smistachkin 
309318507b7Smistachkin #define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \
310318507b7Smistachkin         LPFILETIME))aSyscall[11].pCurrent)
311318507b7Smistachkin 
312318507b7Smistachkin #if SQLITE_OS_WINCE
313318507b7Smistachkin   { "FileTimeToSystemTime",    (SYSCALL)FileTimeToSystemTime,    0 },
314318507b7Smistachkin #else
315318507b7Smistachkin   { "FileTimeToSystemTime",    (SYSCALL)0,                       0 },
316318507b7Smistachkin #endif
317318507b7Smistachkin 
318318507b7Smistachkin #define osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \
319318507b7Smistachkin         LPSYSTEMTIME))aSyscall[12].pCurrent)
320318507b7Smistachkin 
321318507b7Smistachkin   { "FlushFileBuffers",        (SYSCALL)FlushFileBuffers,        0 },
322318507b7Smistachkin 
323318507b7Smistachkin #define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[13].pCurrent)
324318507b7Smistachkin 
325318507b7Smistachkin #if defined(SQLITE_WIN32_HAS_ANSI)
326318507b7Smistachkin   { "FormatMessageA",          (SYSCALL)FormatMessageA,          0 },
327318507b7Smistachkin #else
328318507b7Smistachkin   { "FormatMessageA",          (SYSCALL)0,                       0 },
329318507b7Smistachkin #endif
330318507b7Smistachkin 
331318507b7Smistachkin #define osFormatMessageA ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPSTR, \
332318507b7Smistachkin         DWORD,va_list*))aSyscall[14].pCurrent)
333318507b7Smistachkin 
334318507b7Smistachkin #if defined(SQLITE_WIN32_HAS_WIDE)
335318507b7Smistachkin   { "FormatMessageW",          (SYSCALL)FormatMessageW,          0 },
336318507b7Smistachkin #else
337318507b7Smistachkin   { "FormatMessageW",          (SYSCALL)0,                       0 },
338318507b7Smistachkin #endif
339318507b7Smistachkin 
340318507b7Smistachkin #define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \
341318507b7Smistachkin         DWORD,va_list*))aSyscall[15].pCurrent)
342318507b7Smistachkin 
343318507b7Smistachkin   { "FreeLibrary",             (SYSCALL)FreeLibrary,             0 },
344318507b7Smistachkin 
345318507b7Smistachkin #define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[16].pCurrent)
346318507b7Smistachkin 
347318507b7Smistachkin   { "GetCurrentProcessId",     (SYSCALL)GetCurrentProcessId,     0 },
348318507b7Smistachkin 
349318507b7Smistachkin #define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[17].pCurrent)
350318507b7Smistachkin 
351318507b7Smistachkin #if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI)
352318507b7Smistachkin   { "GetDiskFreeSpaceA",       (SYSCALL)GetDiskFreeSpaceA,       0 },
353318507b7Smistachkin #else
354318507b7Smistachkin   { "GetDiskFreeSpaceA",       (SYSCALL)0,                       0 },
355318507b7Smistachkin #endif
356318507b7Smistachkin 
357318507b7Smistachkin #define osGetDiskFreeSpaceA ((BOOL(WINAPI*)(LPCSTR,LPDWORD,LPDWORD,LPDWORD, \
358318507b7Smistachkin         LPDWORD))aSyscall[18].pCurrent)
359318507b7Smistachkin 
360318507b7Smistachkin #if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
361318507b7Smistachkin   { "GetDiskFreeSpaceW",       (SYSCALL)GetDiskFreeSpaceW,       0 },
362318507b7Smistachkin #else
363318507b7Smistachkin   { "GetDiskFreeSpaceW",       (SYSCALL)0,                       0 },
364318507b7Smistachkin #endif
365318507b7Smistachkin 
366318507b7Smistachkin #define osGetDiskFreeSpaceW ((BOOL(WINAPI*)(LPCWSTR,LPDWORD,LPDWORD,LPDWORD, \
367318507b7Smistachkin         LPDWORD))aSyscall[19].pCurrent)
368318507b7Smistachkin 
369318507b7Smistachkin #if defined(SQLITE_WIN32_HAS_ANSI)
370318507b7Smistachkin   { "GetFileAttributesA",      (SYSCALL)GetFileAttributesA,      0 },
371318507b7Smistachkin #else
372318507b7Smistachkin   { "GetFileAttributesA",      (SYSCALL)0,                       0 },
373318507b7Smistachkin #endif
374318507b7Smistachkin 
375318507b7Smistachkin #define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[20].pCurrent)
376318507b7Smistachkin 
377318507b7Smistachkin #if defined(SQLITE_WIN32_HAS_WIDE)
378318507b7Smistachkin   { "GetFileAttributesW",      (SYSCALL)GetFileAttributesW,      0 },
379318507b7Smistachkin #else
380318507b7Smistachkin   { "GetFileAttributesW",      (SYSCALL)0,                       0 },
381318507b7Smistachkin #endif
382318507b7Smistachkin 
383318507b7Smistachkin #define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[21].pCurrent)
384318507b7Smistachkin 
385318507b7Smistachkin #if defined(SQLITE_WIN32_HAS_WIDE)
386318507b7Smistachkin   { "GetFileAttributesExW",    (SYSCALL)GetFileAttributesExW,    0 },
387318507b7Smistachkin #else
388318507b7Smistachkin   { "GetFileAttributesExW",    (SYSCALL)0,                       0 },
389318507b7Smistachkin #endif
390318507b7Smistachkin 
391318507b7Smistachkin #define osGetFileAttributesExW ((BOOL(WINAPI*)(LPCWSTR,GET_FILEEX_INFO_LEVELS, \
392318507b7Smistachkin         LPVOID))aSyscall[22].pCurrent)
393318507b7Smistachkin 
394318507b7Smistachkin   { "GetFileSize",             (SYSCALL)GetFileSize,             0 },
395318507b7Smistachkin 
396318507b7Smistachkin #define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[23].pCurrent)
397318507b7Smistachkin 
398318507b7Smistachkin #if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI)
399318507b7Smistachkin   { "GetFullPathNameA",        (SYSCALL)GetFullPathNameA,        0 },
400318507b7Smistachkin #else
401318507b7Smistachkin   { "GetFullPathNameA",        (SYSCALL)0,                       0 },
402318507b7Smistachkin #endif
403318507b7Smistachkin 
404318507b7Smistachkin #define osGetFullPathNameA ((DWORD(WINAPI*)(LPCSTR,DWORD,LPSTR, \
405318507b7Smistachkin         LPSTR*))aSyscall[24].pCurrent)
406318507b7Smistachkin 
407318507b7Smistachkin #if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
408318507b7Smistachkin   { "GetFullPathNameW",        (SYSCALL)GetFullPathNameW,        0 },
409318507b7Smistachkin #else
410318507b7Smistachkin   { "GetFullPathNameW",        (SYSCALL)0,                       0 },
411318507b7Smistachkin #endif
412318507b7Smistachkin 
413318507b7Smistachkin #define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \
414318507b7Smistachkin         LPWSTR*))aSyscall[25].pCurrent)
415318507b7Smistachkin 
416318507b7Smistachkin   { "GetLastError",            (SYSCALL)GetLastError,            0 },
417318507b7Smistachkin 
418318507b7Smistachkin #define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent)
419318507b7Smistachkin 
420318507b7Smistachkin #if SQLITE_OS_WINCE
421318507b7Smistachkin   /* The GetProcAddressA() routine is only available on Windows CE. */
422318507b7Smistachkin   { "GetProcAddressA",         (SYSCALL)GetProcAddressA,         0 },
423318507b7Smistachkin #else
424318507b7Smistachkin   /* All other Windows platforms expect GetProcAddress() to take
425318507b7Smistachkin   ** an ANSI string regardless of the _UNICODE setting */
426318507b7Smistachkin   { "GetProcAddressA",         (SYSCALL)GetProcAddress,          0 },
427318507b7Smistachkin #endif
428318507b7Smistachkin 
429318507b7Smistachkin #define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \
430318507b7Smistachkin         LPCSTR))aSyscall[27].pCurrent)
431318507b7Smistachkin 
432318507b7Smistachkin   { "GetSystemInfo",           (SYSCALL)GetSystemInfo,           0 },
433318507b7Smistachkin 
434318507b7Smistachkin #define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[28].pCurrent)
435318507b7Smistachkin 
436318507b7Smistachkin   { "GetSystemTime",           (SYSCALL)GetSystemTime,           0 },
437318507b7Smistachkin 
438318507b7Smistachkin #define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[29].pCurrent)
439318507b7Smistachkin 
440318507b7Smistachkin #if !SQLITE_OS_WINCE
441318507b7Smistachkin   { "GetSystemTimeAsFileTime", (SYSCALL)GetSystemTimeAsFileTime, 0 },
442318507b7Smistachkin #else
443318507b7Smistachkin   { "GetSystemTimeAsFileTime", (SYSCALL)0,                       0 },
444318507b7Smistachkin #endif
445318507b7Smistachkin 
446318507b7Smistachkin #define osGetSystemTimeAsFileTime ((VOID(WINAPI*)( \
447318507b7Smistachkin         LPFILETIME))aSyscall[30].pCurrent)
448318507b7Smistachkin 
449318507b7Smistachkin #if defined(SQLITE_WIN32_HAS_ANSI)
450318507b7Smistachkin   { "GetTempPathA",            (SYSCALL)GetTempPathA,            0 },
451318507b7Smistachkin #else
452318507b7Smistachkin   { "GetTempPathA",            (SYSCALL)0,                       0 },
453318507b7Smistachkin #endif
454318507b7Smistachkin 
455318507b7Smistachkin #define osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[31].pCurrent)
456318507b7Smistachkin 
457318507b7Smistachkin #if defined(SQLITE_WIN32_HAS_WIDE)
458318507b7Smistachkin   { "GetTempPathW",            (SYSCALL)GetTempPathW,            0 },
459318507b7Smistachkin #else
460318507b7Smistachkin   { "GetTempPathW",            (SYSCALL)0,                       0 },
461318507b7Smistachkin #endif
462318507b7Smistachkin 
463318507b7Smistachkin #define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[32].pCurrent)
464318507b7Smistachkin 
465318507b7Smistachkin   { "GetTickCount",            (SYSCALL)GetTickCount,            0 },
466318507b7Smistachkin 
467318507b7Smistachkin #define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent)
468318507b7Smistachkin 
469318507b7Smistachkin #if defined(SQLITE_WIN32_HAS_ANSI)
470318507b7Smistachkin   { "GetVersionExA",           (SYSCALL)GetVersionExA,           0 },
471318507b7Smistachkin #else
472318507b7Smistachkin   { "GetVersionExA",           (SYSCALL)0,                       0 },
473318507b7Smistachkin #endif
474318507b7Smistachkin 
475318507b7Smistachkin #define osGetVersionExA ((BOOL(WINAPI*)( \
476318507b7Smistachkin         LPOSVERSIONINFOA))aSyscall[34].pCurrent)
477318507b7Smistachkin 
478318507b7Smistachkin   { "HeapAlloc",               (SYSCALL)HeapAlloc,               0 },
479318507b7Smistachkin 
480318507b7Smistachkin #define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \
481318507b7Smistachkin         SIZE_T))aSyscall[35].pCurrent)
482318507b7Smistachkin 
483318507b7Smistachkin   { "HeapCreate",              (SYSCALL)HeapCreate,              0 },
484318507b7Smistachkin 
485318507b7Smistachkin #define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \
486318507b7Smistachkin         SIZE_T))aSyscall[36].pCurrent)
487318507b7Smistachkin 
488318507b7Smistachkin   { "HeapDestroy",             (SYSCALL)HeapDestroy,             0 },
489318507b7Smistachkin 
490318507b7Smistachkin #define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[37].pCurrent)
491318507b7Smistachkin 
492318507b7Smistachkin   { "HeapFree",                (SYSCALL)HeapFree,                0 },
493318507b7Smistachkin 
494318507b7Smistachkin #define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[38].pCurrent)
495318507b7Smistachkin 
496318507b7Smistachkin   { "HeapReAlloc",             (SYSCALL)HeapReAlloc,             0 },
497318507b7Smistachkin 
498318507b7Smistachkin #define osHeapReAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD,LPVOID, \
499318507b7Smistachkin         SIZE_T))aSyscall[39].pCurrent)
500318507b7Smistachkin 
501318507b7Smistachkin   { "HeapSize",                (SYSCALL)HeapSize,                0 },
502318507b7Smistachkin 
503318507b7Smistachkin #define osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \
504318507b7Smistachkin         LPCVOID))aSyscall[40].pCurrent)
505318507b7Smistachkin 
506318507b7Smistachkin   { "HeapValidate",            (SYSCALL)HeapValidate,            0 },
507318507b7Smistachkin 
508318507b7Smistachkin #define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \
509318507b7Smistachkin         LPCVOID))aSyscall[41].pCurrent)
510318507b7Smistachkin 
511318507b7Smistachkin #if defined(SQLITE_WIN32_HAS_ANSI)
512318507b7Smistachkin   { "LoadLibraryA",            (SYSCALL)LoadLibraryA,            0 },
513318507b7Smistachkin #else
514318507b7Smistachkin   { "LoadLibraryA",            (SYSCALL)0,                       0 },
515318507b7Smistachkin #endif
516318507b7Smistachkin 
517318507b7Smistachkin #define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[42].pCurrent)
518318507b7Smistachkin 
519318507b7Smistachkin #if defined(SQLITE_WIN32_HAS_WIDE)
520318507b7Smistachkin   { "LoadLibraryW",            (SYSCALL)LoadLibraryW,            0 },
521318507b7Smistachkin #else
522318507b7Smistachkin   { "LoadLibraryW",            (SYSCALL)0,                       0 },
523318507b7Smistachkin #endif
524318507b7Smistachkin 
525318507b7Smistachkin #define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[43].pCurrent)
526318507b7Smistachkin 
527318507b7Smistachkin   { "LocalFree",               (SYSCALL)LocalFree,               0 },
528318507b7Smistachkin 
529318507b7Smistachkin #define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[44].pCurrent)
530318507b7Smistachkin 
531318507b7Smistachkin #if !SQLITE_OS_WINCE
532318507b7Smistachkin   { "LockFile",                (SYSCALL)LockFile,                0 },
533318507b7Smistachkin 
534318507b7Smistachkin #define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
535318507b7Smistachkin         DWORD))aSyscall[45].pCurrent)
536318507b7Smistachkin #else
537318507b7Smistachkin   { "LockFile",                (SYSCALL)0,                       0 },
538318507b7Smistachkin #endif
539318507b7Smistachkin 
540318507b7Smistachkin #if !SQLITE_OS_WINCE
541318507b7Smistachkin   { "LockFileEx",              (SYSCALL)LockFileEx,              0 },
542318507b7Smistachkin 
543318507b7Smistachkin #define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \
544318507b7Smistachkin         LPOVERLAPPED))aSyscall[46].pCurrent)
545318507b7Smistachkin #else
546318507b7Smistachkin   { "LockFileEx",              (SYSCALL)0,                       0 },
547318507b7Smistachkin #endif
548318507b7Smistachkin 
549318507b7Smistachkin   { "MapViewOfFile",           (SYSCALL)MapViewOfFile,           0 },
550318507b7Smistachkin 
551318507b7Smistachkin #define osMapViewOfFile ((LPVOID(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
552318507b7Smistachkin         SIZE_T))aSyscall[47].pCurrent)
553318507b7Smistachkin 
554318507b7Smistachkin   { "MultiByteToWideChar",     (SYSCALL)MultiByteToWideChar,     0 },
555318507b7Smistachkin 
556318507b7Smistachkin #define osMultiByteToWideChar ((int(WINAPI*)(UINT,DWORD,LPCSTR,int,LPWSTR, \
557318507b7Smistachkin         int))aSyscall[48].pCurrent)
558318507b7Smistachkin 
559318507b7Smistachkin   { "QueryPerformanceCounter", (SYSCALL)QueryPerformanceCounter, 0 },
560318507b7Smistachkin 
561318507b7Smistachkin #define osQueryPerformanceCounter ((BOOL(WINAPI*)( \
562318507b7Smistachkin         LARGE_INTEGER*))aSyscall[49].pCurrent)
563318507b7Smistachkin 
564318507b7Smistachkin   { "ReadFile",                (SYSCALL)ReadFile,                0 },
565318507b7Smistachkin 
566318507b7Smistachkin #define osReadFile ((BOOL(WINAPI*)(HANDLE,LPVOID,DWORD,LPDWORD, \
567318507b7Smistachkin         LPOVERLAPPED))aSyscall[50].pCurrent)
568318507b7Smistachkin 
569318507b7Smistachkin   { "SetEndOfFile",            (SYSCALL)SetEndOfFile,            0 },
570318507b7Smistachkin 
571318507b7Smistachkin #define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[51].pCurrent)
572318507b7Smistachkin 
573318507b7Smistachkin   { "SetFilePointer",          (SYSCALL)SetFilePointer,          0 },
574318507b7Smistachkin 
575318507b7Smistachkin #define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \
576318507b7Smistachkin         DWORD))aSyscall[52].pCurrent)
577318507b7Smistachkin 
578318507b7Smistachkin   { "Sleep",                   (SYSCALL)Sleep,                   0 },
579318507b7Smistachkin 
580318507b7Smistachkin #define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[53].pCurrent)
581318507b7Smistachkin 
582318507b7Smistachkin   { "SystemTimeToFileTime",    (SYSCALL)SystemTimeToFileTime,    0 },
583318507b7Smistachkin 
584318507b7Smistachkin #define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \
585318507b7Smistachkin         LPFILETIME))aSyscall[54].pCurrent)
586318507b7Smistachkin 
587318507b7Smistachkin #if !SQLITE_OS_WINCE
588318507b7Smistachkin   { "UnlockFile",              (SYSCALL)UnlockFile,              0 },
589318507b7Smistachkin 
590318507b7Smistachkin #define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
591318507b7Smistachkin         DWORD))aSyscall[55].pCurrent)
592318507b7Smistachkin #else
593318507b7Smistachkin   { "UnlockFile",              (SYSCALL)0,                       0 },
594318507b7Smistachkin #endif
595318507b7Smistachkin 
596318507b7Smistachkin #if !SQLITE_OS_WINCE
597318507b7Smistachkin   { "UnlockFileEx",            (SYSCALL)UnlockFileEx,            0 },
598318507b7Smistachkin 
599318507b7Smistachkin #define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
600318507b7Smistachkin         LPOVERLAPPED))aSyscall[56].pCurrent)
601318507b7Smistachkin #else
602318507b7Smistachkin   { "UnlockFileEx",            (SYSCALL)0,                       0 },
603318507b7Smistachkin #endif
604318507b7Smistachkin 
605318507b7Smistachkin   { "UnmapViewOfFile",         (SYSCALL)UnmapViewOfFile,         0 },
606318507b7Smistachkin 
607318507b7Smistachkin #define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[57].pCurrent)
608318507b7Smistachkin 
609318507b7Smistachkin   { "WideCharToMultiByte",     (SYSCALL)WideCharToMultiByte,     0 },
610318507b7Smistachkin 
611318507b7Smistachkin #define osWideCharToMultiByte ((int(WINAPI*)(UINT,DWORD,LPCWSTR,int,LPSTR,int, \
612318507b7Smistachkin         LPCSTR,LPBOOL))aSyscall[58].pCurrent)
613318507b7Smistachkin 
614318507b7Smistachkin   { "WriteFile",               (SYSCALL)WriteFile,               0 },
615318507b7Smistachkin 
616318507b7Smistachkin #define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \
617318507b7Smistachkin         LPOVERLAPPED))aSyscall[59].pCurrent)
618318507b7Smistachkin 
619318507b7Smistachkin }; /* End of the overrideable system calls */
620318507b7Smistachkin 
621318507b7Smistachkin /*
622318507b7Smistachkin ** This is the xSetSystemCall() method of sqlite3_vfs for all of the
623318507b7Smistachkin ** "win32" VFSes.  Return SQLITE_OK opon successfully updating the
624318507b7Smistachkin ** system call pointer, or SQLITE_NOTFOUND if there is no configurable
625318507b7Smistachkin ** system call named zName.
626318507b7Smistachkin */
627318507b7Smistachkin static int winSetSystemCall(
628318507b7Smistachkin   sqlite3_vfs *pNotUsed,        /* The VFS pointer.  Not used */
629318507b7Smistachkin   const char *zName,            /* Name of system call to override */
630318507b7Smistachkin   sqlite3_syscall_ptr pNewFunc  /* Pointer to new system call value */
631318507b7Smistachkin ){
632318507b7Smistachkin   unsigned int i;
633318507b7Smistachkin   int rc = SQLITE_NOTFOUND;
634318507b7Smistachkin 
635318507b7Smistachkin   UNUSED_PARAMETER(pNotUsed);
636318507b7Smistachkin   if( zName==0 ){
637318507b7Smistachkin     /* If no zName is given, restore all system calls to their default
638318507b7Smistachkin     ** settings and return NULL
639318507b7Smistachkin     */
640318507b7Smistachkin     rc = SQLITE_OK;
641318507b7Smistachkin     for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
642318507b7Smistachkin       if( aSyscall[i].pDefault ){
643318507b7Smistachkin         aSyscall[i].pCurrent = aSyscall[i].pDefault;
644318507b7Smistachkin       }
645318507b7Smistachkin     }
646318507b7Smistachkin   }else{
647318507b7Smistachkin     /* If zName is specified, operate on only the one system call
648318507b7Smistachkin     ** specified.
649318507b7Smistachkin     */
650318507b7Smistachkin     for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
651318507b7Smistachkin       if( strcmp(zName, aSyscall[i].zName)==0 ){
652318507b7Smistachkin         if( aSyscall[i].pDefault==0 ){
653318507b7Smistachkin           aSyscall[i].pDefault = aSyscall[i].pCurrent;
654318507b7Smistachkin         }
655318507b7Smistachkin         rc = SQLITE_OK;
656318507b7Smistachkin         if( pNewFunc==0 ) pNewFunc = aSyscall[i].pDefault;
657318507b7Smistachkin         aSyscall[i].pCurrent = pNewFunc;
658318507b7Smistachkin         break;
659318507b7Smistachkin       }
660318507b7Smistachkin     }
661318507b7Smistachkin   }
662318507b7Smistachkin   return rc;
663318507b7Smistachkin }
664318507b7Smistachkin 
665318507b7Smistachkin /*
666318507b7Smistachkin ** Return the value of a system call.  Return NULL if zName is not a
667318507b7Smistachkin ** recognized system call name.  NULL is also returned if the system call
668318507b7Smistachkin ** is currently undefined.
669318507b7Smistachkin */
670318507b7Smistachkin static sqlite3_syscall_ptr winGetSystemCall(
671318507b7Smistachkin   sqlite3_vfs *pNotUsed,
672318507b7Smistachkin   const char *zName
673318507b7Smistachkin ){
674318507b7Smistachkin   unsigned int i;
675318507b7Smistachkin 
676318507b7Smistachkin   UNUSED_PARAMETER(pNotUsed);
677318507b7Smistachkin   for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
678318507b7Smistachkin     if( strcmp(zName, aSyscall[i].zName)==0 ) return aSyscall[i].pCurrent;
679318507b7Smistachkin   }
680318507b7Smistachkin   return 0;
681318507b7Smistachkin }
682318507b7Smistachkin 
683318507b7Smistachkin /*
684318507b7Smistachkin ** Return the name of the first system call after zName.  If zName==NULL
685318507b7Smistachkin ** then return the name of the first system call.  Return NULL if zName
686318507b7Smistachkin ** is the last system call or if zName is not the name of a valid
687318507b7Smistachkin ** system call.
688318507b7Smistachkin */
689318507b7Smistachkin static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){
690318507b7Smistachkin   int i = -1;
691318507b7Smistachkin 
692318507b7Smistachkin   UNUSED_PARAMETER(p);
693318507b7Smistachkin   if( zName ){
694318507b7Smistachkin     for(i=0; i<ArraySize(aSyscall)-1; i++){
695318507b7Smistachkin       if( strcmp(zName, aSyscall[i].zName)==0 ) break;
696318507b7Smistachkin     }
697318507b7Smistachkin   }
698318507b7Smistachkin   for(i++; i<ArraySize(aSyscall); i++){
699318507b7Smistachkin     if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
700318507b7Smistachkin   }
701318507b7Smistachkin   return 0;
702318507b7Smistachkin }
703318507b7Smistachkin 
704318507b7Smistachkin /*
705cc78fea4Sdrh ** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
706cc78fea4Sdrh ** or WinCE.  Return false (zero) for Win95, Win98, or WinME.
707c0929987Sdrh **
708c0929987Sdrh ** Here is an interesting observation:  Win95, Win98, and WinME lack
709c0929987Sdrh ** the LockFileEx() API.  But we can still statically link against that
71050daafc7Sshane ** API as long as we don't call it when running Win95/98/ME.  A call to
711c0929987Sdrh ** this routine is used to determine if the host is Win95/98/ME or
712c0929987Sdrh ** WinNT/2K/XP so that we will know whether or not we can safely call
713c0929987Sdrh ** the LockFileEx() API.
714c0929987Sdrh */
71529bafeabSdanielk1977 #if SQLITE_OS_WINCE
716cc78fea4Sdrh # define isNT()  (1)
717cc78fea4Sdrh #else
718c0929987Sdrh   static int isNT(void){
719c0929987Sdrh     if( sqlite3_os_type==0 ){
720318507b7Smistachkin       OSVERSIONINFOA sInfo;
721c0929987Sdrh       sInfo.dwOSVersionInfoSize = sizeof(sInfo);
722318507b7Smistachkin       osGetVersionExA(&sInfo);
723c0929987Sdrh       sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
724c0929987Sdrh     }
725c0929987Sdrh     return sqlite3_os_type==2;
726c0929987Sdrh   }
72729bafeabSdanielk1977 #endif /* SQLITE_OS_WINCE */
728cc78fea4Sdrh 
7291b186a99Smistachkin #ifdef SQLITE_WIN32_MALLOC
7301b186a99Smistachkin /*
7311b186a99Smistachkin ** Allocate nBytes of memory.
7321b186a99Smistachkin */
7331b186a99Smistachkin static void *winMemMalloc(int nBytes){
7341b186a99Smistachkin   HANDLE hHeap;
735468690efSmistachkin   void *p;
7361b186a99Smistachkin 
737468690efSmistachkin   winMemAssertMagic();
738468690efSmistachkin   hHeap = winMemGetHeap();
7391b186a99Smistachkin   assert( hHeap!=0 );
7401b186a99Smistachkin   assert( hHeap!=INVALID_HANDLE_VALUE );
7411b186a99Smistachkin #ifdef SQLITE_WIN32_MALLOC_VALIDATE
742318507b7Smistachkin   assert ( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
7431b186a99Smistachkin #endif
7441b186a99Smistachkin   assert( nBytes>=0 );
745318507b7Smistachkin   p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
746468690efSmistachkin   if( !p ){
747468690efSmistachkin     sqlite3_log(SQLITE_NOMEM, "failed to HeapAlloc %u bytes (%d), heap=%p",
748318507b7Smistachkin                 nBytes, osGetLastError(), (void*)hHeap);
749468690efSmistachkin   }
750468690efSmistachkin   return p;
7511b186a99Smistachkin }
7521b186a99Smistachkin 
7531b186a99Smistachkin /*
7541b186a99Smistachkin ** Free memory.
7551b186a99Smistachkin */
7561b186a99Smistachkin static void winMemFree(void *pPrior){
7571b186a99Smistachkin   HANDLE hHeap;
7581b186a99Smistachkin 
759468690efSmistachkin   winMemAssertMagic();
760468690efSmistachkin   hHeap = winMemGetHeap();
7611b186a99Smistachkin   assert( hHeap!=0 );
7621b186a99Smistachkin   assert( hHeap!=INVALID_HANDLE_VALUE );
7631b186a99Smistachkin #ifdef SQLITE_WIN32_MALLOC_VALIDATE
764318507b7Smistachkin   assert ( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) );
7651b186a99Smistachkin #endif
7661b186a99Smistachkin   if( !pPrior ) return; /* Passing NULL to HeapFree is undefined. */
767318507b7Smistachkin   if( !osHeapFree(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ){
768468690efSmistachkin     sqlite3_log(SQLITE_NOMEM, "failed to HeapFree block %p (%d), heap=%p",
769318507b7Smistachkin                 pPrior, osGetLastError(), (void*)hHeap);
770468690efSmistachkin   }
7711b186a99Smistachkin }
7721b186a99Smistachkin 
7731b186a99Smistachkin /*
7741b186a99Smistachkin ** Change the size of an existing memory allocation
7751b186a99Smistachkin */
7761b186a99Smistachkin static void *winMemRealloc(void *pPrior, int nBytes){
7771b186a99Smistachkin   HANDLE hHeap;
778468690efSmistachkin   void *p;
7791b186a99Smistachkin 
780468690efSmistachkin   winMemAssertMagic();
781468690efSmistachkin   hHeap = winMemGetHeap();
7821b186a99Smistachkin   assert( hHeap!=0 );
7831b186a99Smistachkin   assert( hHeap!=INVALID_HANDLE_VALUE );
7841b186a99Smistachkin #ifdef SQLITE_WIN32_MALLOC_VALIDATE
785318507b7Smistachkin   assert ( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) );
7861b186a99Smistachkin #endif
7871b186a99Smistachkin   assert( nBytes>=0 );
788468690efSmistachkin   if( !pPrior ){
789318507b7Smistachkin     p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
790468690efSmistachkin   }else{
791318507b7Smistachkin     p = osHeapReAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior, (SIZE_T)nBytes);
792468690efSmistachkin   }
793468690efSmistachkin   if( !p ){
794468690efSmistachkin     sqlite3_log(SQLITE_NOMEM, "failed to %s %u bytes (%d), heap=%p",
795318507b7Smistachkin                 pPrior ? "HeapReAlloc" : "HeapAlloc", nBytes, osGetLastError(),
796468690efSmistachkin                 (void*)hHeap);
797468690efSmistachkin   }
798468690efSmistachkin   return p;
7991b186a99Smistachkin }
8001b186a99Smistachkin 
8011b186a99Smistachkin /*
8021b186a99Smistachkin ** Return the size of an outstanding allocation, in bytes.
8031b186a99Smistachkin */
8041b186a99Smistachkin static int winMemSize(void *p){
8051b186a99Smistachkin   HANDLE hHeap;
8061b186a99Smistachkin   SIZE_T n;
8071b186a99Smistachkin 
808468690efSmistachkin   winMemAssertMagic();
809468690efSmistachkin   hHeap = winMemGetHeap();
8101b186a99Smistachkin   assert( hHeap!=0 );
8111b186a99Smistachkin   assert( hHeap!=INVALID_HANDLE_VALUE );
8121b186a99Smistachkin #ifdef SQLITE_WIN32_MALLOC_VALIDATE
813318507b7Smistachkin   assert ( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
8141b186a99Smistachkin #endif
8151b186a99Smistachkin   if( !p ) return 0;
816318507b7Smistachkin   n = osHeapSize(hHeap, SQLITE_WIN32_HEAP_FLAGS, p);
817468690efSmistachkin   if( n==(SIZE_T)-1 ){
818468690efSmistachkin     sqlite3_log(SQLITE_NOMEM, "failed to HeapSize block %p (%d), heap=%p",
819318507b7Smistachkin                 p, osGetLastError(), (void*)hHeap);
820468690efSmistachkin     return 0;
821468690efSmistachkin   }
8221b186a99Smistachkin   return (int)n;
8231b186a99Smistachkin }
8241b186a99Smistachkin 
8251b186a99Smistachkin /*
8261b186a99Smistachkin ** Round up a request size to the next valid allocation size.
8271b186a99Smistachkin */
8281b186a99Smistachkin static int winMemRoundup(int n){
8291b186a99Smistachkin   return n;
8301b186a99Smistachkin }
8311b186a99Smistachkin 
8321b186a99Smistachkin /*
8331b186a99Smistachkin ** Initialize this module.
8341b186a99Smistachkin */
8351b186a99Smistachkin static int winMemInit(void *pAppData){
8361b186a99Smistachkin   winMemData *pWinMemData = (winMemData *)pAppData;
8371b186a99Smistachkin 
8381b186a99Smistachkin   if( !pWinMemData ) return SQLITE_ERROR;
8391b186a99Smistachkin   assert( pWinMemData->magic==WINMEM_MAGIC );
8401b186a99Smistachkin   if( !pWinMemData->hHeap ){
841318507b7Smistachkin     pWinMemData->hHeap = osHeapCreate(SQLITE_WIN32_HEAP_FLAGS,
842155892ccSmistachkin                                       SQLITE_WIN32_HEAP_INIT_SIZE,
8431b186a99Smistachkin                                       SQLITE_WIN32_HEAP_MAX_SIZE);
8441b186a99Smistachkin     if( !pWinMemData->hHeap ){
845468690efSmistachkin       sqlite3_log(SQLITE_NOMEM,
846155892ccSmistachkin           "failed to HeapCreate (%d), flags=%u, initSize=%u, maxSize=%u",
847318507b7Smistachkin           osGetLastError(), SQLITE_WIN32_HEAP_FLAGS,
848318507b7Smistachkin           SQLITE_WIN32_HEAP_INIT_SIZE, SQLITE_WIN32_HEAP_MAX_SIZE);
8491b186a99Smistachkin       return SQLITE_NOMEM;
8501b186a99Smistachkin     }
8511b186a99Smistachkin     pWinMemData->bOwned = TRUE;
8521b186a99Smistachkin   }
8531b186a99Smistachkin   assert( pWinMemData->hHeap!=0 );
8541b186a99Smistachkin   assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE );
8551b186a99Smistachkin #ifdef SQLITE_WIN32_MALLOC_VALIDATE
856318507b7Smistachkin   assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
8571b186a99Smistachkin #endif
8581b186a99Smistachkin   return SQLITE_OK;
8591b186a99Smistachkin }
8601b186a99Smistachkin 
8611b186a99Smistachkin /*
8621b186a99Smistachkin ** Deinitialize this module.
8631b186a99Smistachkin */
8641b186a99Smistachkin static void winMemShutdown(void *pAppData){
8651b186a99Smistachkin   winMemData *pWinMemData = (winMemData *)pAppData;
8661b186a99Smistachkin 
8671b186a99Smistachkin   if( !pWinMemData ) return;
8681b186a99Smistachkin   if( pWinMemData->hHeap ){
8691b186a99Smistachkin     assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE );
8701b186a99Smistachkin #ifdef SQLITE_WIN32_MALLOC_VALIDATE
871318507b7Smistachkin     assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
8721b186a99Smistachkin #endif
8731b186a99Smistachkin     if( pWinMemData->bOwned ){
874318507b7Smistachkin       if( !osHeapDestroy(pWinMemData->hHeap) ){
875468690efSmistachkin         sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%d), heap=%p",
876318507b7Smistachkin                     osGetLastError(), (void*)pWinMemData->hHeap);
8771b186a99Smistachkin       }
8781b186a99Smistachkin       pWinMemData->bOwned = FALSE;
8791b186a99Smistachkin     }
8801b186a99Smistachkin     pWinMemData->hHeap = NULL;
8811b186a99Smistachkin   }
8821b186a99Smistachkin }
8831b186a99Smistachkin 
8841b186a99Smistachkin /*
8851b186a99Smistachkin ** Populate the low-level memory allocation function pointers in
8861b186a99Smistachkin ** sqlite3GlobalConfig.m with pointers to the routines in this file. The
8871b186a99Smistachkin ** arguments specify the block of memory to manage.
8881b186a99Smistachkin **
8891b186a99Smistachkin ** This routine is only called by sqlite3_config(), and therefore
8901b186a99Smistachkin ** is not required to be threadsafe (it is not).
8911b186a99Smistachkin */
8921b186a99Smistachkin const sqlite3_mem_methods *sqlite3MemGetWin32(void){
8931b186a99Smistachkin   static const sqlite3_mem_methods winMemMethods = {
8941b186a99Smistachkin     winMemMalloc,
8951b186a99Smistachkin     winMemFree,
8961b186a99Smistachkin     winMemRealloc,
8971b186a99Smistachkin     winMemSize,
8981b186a99Smistachkin     winMemRoundup,
8991b186a99Smistachkin     winMemInit,
9001b186a99Smistachkin     winMemShutdown,
9011b186a99Smistachkin     &win_mem_data
9021b186a99Smistachkin   };
9031b186a99Smistachkin   return &winMemMethods;
9041b186a99Smistachkin }
9051b186a99Smistachkin 
9061b186a99Smistachkin void sqlite3MemSetDefault(void){
9071b186a99Smistachkin   sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetWin32());
9081b186a99Smistachkin }
9091b186a99Smistachkin #endif /* SQLITE_WIN32_MALLOC */
9101b186a99Smistachkin 
911c0929987Sdrh /*
912318507b7Smistachkin ** Convert a UTF-8 string to Microsoft Unicode (UTF-16?).
913584c094bSdrh **
914b11caac3Sdrh ** Space to hold the returned string is obtained from malloc.
915c0929987Sdrh */
916318507b7Smistachkin static LPWSTR utf8ToUnicode(const char *zFilename){
917e3dd8bb5Sdrh   int nChar;
918318507b7Smistachkin   LPWSTR zWideFilename;
919c0929987Sdrh 
920318507b7Smistachkin   nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
921*6ca514b0Smistachkin   if( nChar==0 ){
922*6ca514b0Smistachkin     return 0;
923*6ca514b0Smistachkin   }
9245f075388Smistachkin   zWideFilename = sqlite3_malloc( nChar*sizeof(zWideFilename[0]) );
925c0929987Sdrh   if( zWideFilename==0 ){
926c0929987Sdrh     return 0;
927c0929987Sdrh   }
928318507b7Smistachkin   nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
929318507b7Smistachkin                                 nChar);
930e3dd8bb5Sdrh   if( nChar==0 ){
9315f075388Smistachkin     sqlite3_free(zWideFilename);
932c0929987Sdrh     zWideFilename = 0;
933c0929987Sdrh   }
934c0929987Sdrh   return zWideFilename;
935c0929987Sdrh }
936c0929987Sdrh 
937c0929987Sdrh /*
938318507b7Smistachkin ** Convert Microsoft Unicode to UTF-8.  Space to hold the returned string is
9395f075388Smistachkin ** obtained from sqlite3_malloc().
940c0929987Sdrh */
941318507b7Smistachkin static char *unicodeToUtf8(LPCWSTR zWideFilename){
942c0929987Sdrh   int nByte;
943c0929987Sdrh   char *zFilename;
944c0929987Sdrh 
945318507b7Smistachkin   nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
946*6ca514b0Smistachkin   if( nByte == 0 ){
947*6ca514b0Smistachkin     return 0;
948*6ca514b0Smistachkin   }
9495f075388Smistachkin   zFilename = sqlite3_malloc( nByte );
950c0929987Sdrh   if( zFilename==0 ){
951c0929987Sdrh     return 0;
952c0929987Sdrh   }
953318507b7Smistachkin   nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
954c0929987Sdrh                                 0, 0);
955c0929987Sdrh   if( nByte == 0 ){
9565f075388Smistachkin     sqlite3_free(zFilename);
957c0929987Sdrh     zFilename = 0;
958c0929987Sdrh   }
959c0929987Sdrh   return zFilename;
960c0929987Sdrh }
961c0929987Sdrh 
962371de5adSdrh /*
9636c3c1a09Smistachkin ** Convert an ANSI string to Microsoft Unicode, based on the
964584c094bSdrh ** current codepage settings for file apis.
965584c094bSdrh **
966584c094bSdrh ** Space to hold the returned string is obtained
9675f075388Smistachkin ** from sqlite3_malloc.
968371de5adSdrh */
969318507b7Smistachkin static LPWSTR mbcsToUnicode(const char *zFilename){
970371de5adSdrh   int nByte;
971318507b7Smistachkin   LPWSTR zMbcsFilename;
972318507b7Smistachkin   int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
973371de5adSdrh 
974318507b7Smistachkin   nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, NULL,
975318507b7Smistachkin                                 0)*sizeof(WCHAR);
976*6ca514b0Smistachkin   if( nByte==0 ){
977*6ca514b0Smistachkin     return 0;
978*6ca514b0Smistachkin   }
9795f075388Smistachkin   zMbcsFilename = sqlite3_malloc( nByte*sizeof(zMbcsFilename[0]) );
980371de5adSdrh   if( zMbcsFilename==0 ){
981371de5adSdrh     return 0;
982371de5adSdrh   }
983318507b7Smistachkin   nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename,
984318507b7Smistachkin                                 nByte);
985371de5adSdrh   if( nByte==0 ){
9865f075388Smistachkin     sqlite3_free(zMbcsFilename);
987371de5adSdrh     zMbcsFilename = 0;
988371de5adSdrh   }
989371de5adSdrh   return zMbcsFilename;
990371de5adSdrh }
991371de5adSdrh 
992371de5adSdrh /*
993318507b7Smistachkin ** Convert Microsoft Unicode to multi-byte character string, based on the
994318507b7Smistachkin ** user's ANSI codepage.
995584c094bSdrh **
996584c094bSdrh ** Space to hold the returned string is obtained from
9975f075388Smistachkin ** sqlite3_malloc().
998371de5adSdrh */
999318507b7Smistachkin static char *unicodeToMbcs(LPCWSTR zWideFilename){
1000371de5adSdrh   int nByte;
1001371de5adSdrh   char *zFilename;
1002318507b7Smistachkin   int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
1003371de5adSdrh 
1004318507b7Smistachkin   nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
1005*6ca514b0Smistachkin   if( nByte == 0 ){
1006*6ca514b0Smistachkin     return 0;
1007*6ca514b0Smistachkin   }
10085f075388Smistachkin   zFilename = sqlite3_malloc( nByte );
1009371de5adSdrh   if( zFilename==0 ){
1010371de5adSdrh     return 0;
1011371de5adSdrh   }
1012318507b7Smistachkin   nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename,
1013318507b7Smistachkin                                 nByte, 0, 0);
1014371de5adSdrh   if( nByte == 0 ){
10155f075388Smistachkin     sqlite3_free(zFilename);
1016371de5adSdrh     zFilename = 0;
1017371de5adSdrh   }
1018371de5adSdrh   return zFilename;
1019371de5adSdrh }
1020371de5adSdrh 
1021371de5adSdrh /*
1022371de5adSdrh ** Convert multibyte character string to UTF-8.  Space to hold the
10235f075388Smistachkin ** returned string is obtained from sqlite3_malloc().
1024371de5adSdrh */
10251d298855Sdrh char *sqlite3_win32_mbcs_to_utf8(const char *zFilename){
1026371de5adSdrh   char *zFilenameUtf8;
1027318507b7Smistachkin   LPWSTR zTmpWide;
1028371de5adSdrh 
1029371de5adSdrh   zTmpWide = mbcsToUnicode(zFilename);
1030371de5adSdrh   if( zTmpWide==0 ){
1031371de5adSdrh     return 0;
1032371de5adSdrh   }
1033371de5adSdrh   zFilenameUtf8 = unicodeToUtf8(zTmpWide);
10345f075388Smistachkin   sqlite3_free(zTmpWide);
1035371de5adSdrh   return zFilenameUtf8;
1036371de5adSdrh }
1037371de5adSdrh 
1038371de5adSdrh /*
1039371de5adSdrh ** Convert UTF-8 to multibyte character string.  Space to hold the
10405f075388Smistachkin ** returned string is obtained from sqlite3_malloc().
1041371de5adSdrh */
10425b92f192Sdrh char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){
1043371de5adSdrh   char *zFilenameMbcs;
1044318507b7Smistachkin   LPWSTR zTmpWide;
1045371de5adSdrh 
1046371de5adSdrh   zTmpWide = utf8ToUnicode(zFilename);
1047371de5adSdrh   if( zTmpWide==0 ){
1048371de5adSdrh     return 0;
1049371de5adSdrh   }
1050371de5adSdrh   zFilenameMbcs = unicodeToMbcs(zTmpWide);
10515f075388Smistachkin   sqlite3_free(zTmpWide);
1052371de5adSdrh   return zFilenameMbcs;
1053371de5adSdrh }
1054371de5adSdrh 
105550990dbbSdrh 
105650990dbbSdrh /*
105750990dbbSdrh ** The return value of getLastErrorMsg
105850990dbbSdrh ** is zero if the error message fits in the buffer, or non-zero
105950990dbbSdrh ** otherwise (if the message was truncated).
106050990dbbSdrh */
1061a9664a14Smistachkin static int getLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){
106250990dbbSdrh   /* FormatMessage returns 0 on failure.  Otherwise it
106350990dbbSdrh   ** returns the number of TCHARs written to the output
106450990dbbSdrh   ** buffer, excluding the terminating null char.
106550990dbbSdrh   */
106650990dbbSdrh   DWORD dwLen = 0;
106750990dbbSdrh   char *zOut = 0;
106850990dbbSdrh 
106950990dbbSdrh   if( isNT() ){
1070318507b7Smistachkin     LPWSTR zTempWide = NULL;
1071318507b7Smistachkin     dwLen = osFormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1072a9664a14Smistachkin                              FORMAT_MESSAGE_FROM_SYSTEM |
1073a9664a14Smistachkin                              FORMAT_MESSAGE_IGNORE_INSERTS,
107450990dbbSdrh                              NULL,
1075a9664a14Smistachkin                              lastErrno,
107650990dbbSdrh                              0,
107750990dbbSdrh                              (LPWSTR) &zTempWide,
107850990dbbSdrh                              0,
107950990dbbSdrh                              0);
108050990dbbSdrh     if( dwLen > 0 ){
108150990dbbSdrh       /* allocate a buffer and convert to UTF8 */
10826c3c1a09Smistachkin       sqlite3BeginBenignMalloc();
108350990dbbSdrh       zOut = unicodeToUtf8(zTempWide);
10846c3c1a09Smistachkin       sqlite3EndBenignMalloc();
108550990dbbSdrh       /* free the system buffer allocated by FormatMessage */
1086318507b7Smistachkin       osLocalFree(zTempWide);
108750990dbbSdrh     }
108850990dbbSdrh /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
10896c3c1a09Smistachkin ** Since the ANSI version of these Windows API do not exist for WINCE,
109050990dbbSdrh ** it's important to not reference them for WINCE builds.
109150990dbbSdrh */
109250990dbbSdrh #if SQLITE_OS_WINCE==0
109350990dbbSdrh   }else{
109450990dbbSdrh     char *zTemp = NULL;
1095318507b7Smistachkin     dwLen = osFormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1096a9664a14Smistachkin                              FORMAT_MESSAGE_FROM_SYSTEM |
1097a9664a14Smistachkin                              FORMAT_MESSAGE_IGNORE_INSERTS,
109850990dbbSdrh                              NULL,
1099a9664a14Smistachkin                              lastErrno,
110050990dbbSdrh                              0,
110150990dbbSdrh                              (LPSTR) &zTemp,
110250990dbbSdrh                              0,
110350990dbbSdrh                              0);
110450990dbbSdrh     if( dwLen > 0 ){
110550990dbbSdrh       /* allocate a buffer and convert to UTF8 */
11066c3c1a09Smistachkin       sqlite3BeginBenignMalloc();
110750990dbbSdrh       zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
11086c3c1a09Smistachkin       sqlite3EndBenignMalloc();
110950990dbbSdrh       /* free the system buffer allocated by FormatMessage */
1110318507b7Smistachkin       osLocalFree(zTemp);
111150990dbbSdrh     }
111250990dbbSdrh #endif
111350990dbbSdrh   }
111450990dbbSdrh   if( 0 == dwLen ){
1115a9664a14Smistachkin     sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", lastErrno, lastErrno);
111650990dbbSdrh   }else{
111750990dbbSdrh     /* copy a maximum of nBuf chars to output buffer */
111850990dbbSdrh     sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
111950990dbbSdrh     /* free the UTF8 buffer */
11205f075388Smistachkin     sqlite3_free(zOut);
112150990dbbSdrh   }
112250990dbbSdrh   return 0;
112350990dbbSdrh }
112450990dbbSdrh 
112550990dbbSdrh /*
112650990dbbSdrh **
112750990dbbSdrh ** This function - winLogErrorAtLine() - is only ever called via the macro
112850990dbbSdrh ** winLogError().
112950990dbbSdrh **
113050990dbbSdrh ** This routine is invoked after an error occurs in an OS function.
113150990dbbSdrh ** It logs a message using sqlite3_log() containing the current value of
113250990dbbSdrh ** error code and, if possible, the human-readable equivalent from
113350990dbbSdrh ** FormatMessage.
113450990dbbSdrh **
113550990dbbSdrh ** The first argument passed to the macro should be the error code that
113650990dbbSdrh ** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN).
113750990dbbSdrh ** The two subsequent arguments should be the name of the OS function that
113850990dbbSdrh ** failed and the the associated file-system path, if any.
113950990dbbSdrh */
11402aef997cSmistachkin #define winLogError(a,b,c,d)   winLogErrorAtLine(a,b,c,d,__LINE__)
114150990dbbSdrh static int winLogErrorAtLine(
114250990dbbSdrh   int errcode,                    /* SQLite error code */
11432aef997cSmistachkin   DWORD lastErrno,                /* Win32 last error */
114450990dbbSdrh   const char *zFunc,              /* Name of OS function that failed */
114550990dbbSdrh   const char *zPath,              /* File path associated with error */
114650990dbbSdrh   int iLine                       /* Source line number where error occurred */
114750990dbbSdrh ){
114850990dbbSdrh   char zMsg[500];                 /* Human readable error text */
11495f2dfdbcSdrh   int i;                          /* Loop counter */
115050990dbbSdrh 
115150990dbbSdrh   zMsg[0] = 0;
1152a9664a14Smistachkin   getLastErrorMsg(lastErrno, sizeof(zMsg), zMsg);
115350990dbbSdrh   assert( errcode!=SQLITE_OK );
115450990dbbSdrh   if( zPath==0 ) zPath = "";
11555f2dfdbcSdrh   for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){}
11565f2dfdbcSdrh   zMsg[i] = 0;
115750990dbbSdrh   sqlite3_log(errcode,
115850990dbbSdrh       "os_win.c:%d: (%d) %s(%s) - %s",
11592aef997cSmistachkin       iLine, lastErrno, zFunc, zPath, zMsg
116050990dbbSdrh   );
116150990dbbSdrh 
116250990dbbSdrh   return errcode;
116350990dbbSdrh }
116450990dbbSdrh 
11655d9ef0a6Sdrh /*
116652564d70Sdrh ** The number of times that a ReadFile(), WriteFile(), and DeleteFile()
116752564d70Sdrh ** will be retried following a locking error - probably caused by
116852564d70Sdrh ** antivirus software.  Also the initial delay before the first retry.
116952564d70Sdrh ** The delay increases linearly with each retry.
11705d9ef0a6Sdrh */
11715d9ef0a6Sdrh #ifndef SQLITE_WIN32_IOERR_RETRY
117252564d70Sdrh # define SQLITE_WIN32_IOERR_RETRY 10
117352564d70Sdrh #endif
117452564d70Sdrh #ifndef SQLITE_WIN32_IOERR_RETRY_DELAY
117552564d70Sdrh # define SQLITE_WIN32_IOERR_RETRY_DELAY 25
11765d9ef0a6Sdrh #endif
1177d0cdf012Sdrh static int win32IoerrRetry = SQLITE_WIN32_IOERR_RETRY;
1178d0cdf012Sdrh static int win32IoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY;
11795d9ef0a6Sdrh 
11805d9ef0a6Sdrh /*
11815d9ef0a6Sdrh ** If a ReadFile() or WriteFile() error occurs, invoke this routine
11825d9ef0a6Sdrh ** to see if it should be retried.  Return TRUE to retry.  Return FALSE
11835d9ef0a6Sdrh ** to give up with an error.
11845d9ef0a6Sdrh */
1185d1ef9b6dSmistachkin static int retryIoerr(int *pnRetry, DWORD *pError){
1186d1ef9b6dSmistachkin   DWORD e = osGetLastError();
1187d0cdf012Sdrh   if( *pnRetry>=win32IoerrRetry ){
1188d1ef9b6dSmistachkin     if( pError ){
1189d1ef9b6dSmistachkin       *pError = e;
1190d1ef9b6dSmistachkin     }
11915d9ef0a6Sdrh     return 0;
11925d9ef0a6Sdrh   }
1193dc9e9587Smistachkin   if( e==ERROR_ACCESS_DENIED ||
1194dc9e9587Smistachkin       e==ERROR_LOCK_VIOLATION ||
1195dc9e9587Smistachkin       e==ERROR_SHARING_VIOLATION ){
1196318507b7Smistachkin     osSleep(win32IoerrRetryDelay*(1+*pnRetry));
11975d9ef0a6Sdrh     ++*pnRetry;
11985d9ef0a6Sdrh     return 1;
11995d9ef0a6Sdrh   }
1200d1ef9b6dSmistachkin   if( pError ){
1201d1ef9b6dSmistachkin     *pError = e;
1202d1ef9b6dSmistachkin   }
12035d9ef0a6Sdrh   return 0;
12045d9ef0a6Sdrh }
12055d9ef0a6Sdrh 
1206a32ad843Sdrh /*
1207a32ad843Sdrh ** Log a I/O error retry episode.
1208a32ad843Sdrh */
1209a32ad843Sdrh static void logIoerr(int nRetry){
1210a32ad843Sdrh   if( nRetry ){
1211a32ad843Sdrh     sqlite3_log(SQLITE_IOERR,
1212a32ad843Sdrh       "delayed %dms for lock/sharing conflict",
1213d0cdf012Sdrh       win32IoerrRetryDelay*nRetry*(nRetry+1)/2
1214a32ad843Sdrh     );
1215a32ad843Sdrh   }
1216a32ad843Sdrh }
1217a32ad843Sdrh 
121829bafeabSdanielk1977 #if SQLITE_OS_WINCE
121972aead81Sdrh /*************************************************************************
122072aead81Sdrh ** This section contains code for WinCE only.
122172aead81Sdrh */
122272aead81Sdrh /*
122372aead81Sdrh ** Windows CE does not have a localtime() function.  So create a
122472aead81Sdrh ** substitute.
122572aead81Sdrh */
122672aead81Sdrh #include <time.h>
122772aead81Sdrh struct tm *__cdecl localtime(const time_t *t)
122872aead81Sdrh {
122972aead81Sdrh   static struct tm y;
123072aead81Sdrh   FILETIME uTm, lTm;
123172aead81Sdrh   SYSTEMTIME pTm;
1232c51250a5Sdrh   sqlite3_int64 t64;
123372aead81Sdrh   t64 = *t;
123472aead81Sdrh   t64 = (t64 + 11644473600)*10000000;
1235d87873d1Sshane   uTm.dwLowDateTime = (DWORD)(t64 & 0xFFFFFFFF);
1236d87873d1Sshane   uTm.dwHighDateTime= (DWORD)(t64 >> 32);
1237318507b7Smistachkin   osFileTimeToLocalFileTime(&uTm,&lTm);
1238318507b7Smistachkin   osFileTimeToSystemTime(&lTm,&pTm);
123972aead81Sdrh   y.tm_year = pTm.wYear - 1900;
124072aead81Sdrh   y.tm_mon = pTm.wMonth - 1;
124172aead81Sdrh   y.tm_wday = pTm.wDayOfWeek;
124272aead81Sdrh   y.tm_mday = pTm.wDay;
124372aead81Sdrh   y.tm_hour = pTm.wHour;
124472aead81Sdrh   y.tm_min = pTm.wMinute;
124572aead81Sdrh   y.tm_sec = pTm.wSecond;
124672aead81Sdrh   return &y;
124772aead81Sdrh }
124872aead81Sdrh 
1249d87873d1Sshane #define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
125072aead81Sdrh 
125172aead81Sdrh /*
125272aead81Sdrh ** Acquire a lock on the handle h
125372aead81Sdrh */
125472aead81Sdrh static void winceMutexAcquire(HANDLE h){
125572aead81Sdrh    DWORD dwErr;
125672aead81Sdrh    do {
125772aead81Sdrh      dwErr = WaitForSingleObject(h, INFINITE);
125872aead81Sdrh    } while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED);
125972aead81Sdrh }
126072aead81Sdrh /*
126172aead81Sdrh ** Release a lock acquired by winceMutexAcquire()
126272aead81Sdrh */
126372aead81Sdrh #define winceMutexRelease(h) ReleaseMutex(h)
126472aead81Sdrh 
126572aead81Sdrh /*
126672aead81Sdrh ** Create the mutex and shared memory used for locking in the file
126772aead81Sdrh ** descriptor pFile
126872aead81Sdrh */
126972aead81Sdrh static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
1270318507b7Smistachkin   LPWSTR zTok;
12715f075388Smistachkin   LPWSTR zName;
127272aead81Sdrh   BOOL bInit = TRUE;
127372aead81Sdrh 
12745f075388Smistachkin   zName = utf8ToUnicode(zFilename);
12755f075388Smistachkin   if( zName==0 ){
12765f075388Smistachkin     /* out of memory */
12775f075388Smistachkin     return FALSE;
12785f075388Smistachkin   }
12795f075388Smistachkin 
128072aead81Sdrh   /* Initialize the local lockdata */
1281318507b7Smistachkin   memset(&pFile->local, 0, sizeof(pFile->local));
128272aead81Sdrh 
128372aead81Sdrh   /* Replace the backslashes from the filename and lowercase it
128472aead81Sdrh   ** to derive a mutex name. */
1285318507b7Smistachkin   zTok = osCharLowerW(zName);
128672aead81Sdrh   for (;*zTok;zTok++){
128772aead81Sdrh     if (*zTok == '\\') *zTok = '_';
128872aead81Sdrh   }
128972aead81Sdrh 
129072aead81Sdrh   /* Create/open the named mutex */
1291318507b7Smistachkin   pFile->hMutex = osCreateMutexW(NULL, FALSE, zName);
129272aead81Sdrh   if (!pFile->hMutex){
1293318507b7Smistachkin     pFile->lastErrno = osGetLastError();
12942aef997cSmistachkin     winLogError(SQLITE_ERROR, pFile->lastErrno, "winceCreateLock1", zFilename);
12955f075388Smistachkin     sqlite3_free(zName);
129672aead81Sdrh     return FALSE;
129772aead81Sdrh   }
129872aead81Sdrh 
129972aead81Sdrh   /* Acquire the mutex before continuing */
130072aead81Sdrh   winceMutexAcquire(pFile->hMutex);
130172aead81Sdrh 
130272aead81Sdrh   /* Since the names of named mutexes, semaphores, file mappings etc are
130372aead81Sdrh   ** case-sensitive, take advantage of that by uppercasing the mutex name
130472aead81Sdrh   ** and using that as the shared filemapping name.
130572aead81Sdrh   */
1306318507b7Smistachkin   osCharUpperW(zName);
1307318507b7Smistachkin   pFile->hShared = osCreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
130872aead81Sdrh                                         PAGE_READWRITE, 0, sizeof(winceLock),
130972aead81Sdrh                                         zName);
131072aead81Sdrh 
131172aead81Sdrh   /* Set a flag that indicates we're the first to create the memory so it
131272aead81Sdrh   ** must be zero-initialized */
1313318507b7Smistachkin   if (osGetLastError() == ERROR_ALREADY_EXISTS){
131472aead81Sdrh     bInit = FALSE;
131572aead81Sdrh   }
131672aead81Sdrh 
13175f075388Smistachkin   sqlite3_free(zName);
131872aead81Sdrh 
131972aead81Sdrh   /* If we succeeded in making the shared memory handle, map it. */
132072aead81Sdrh   if (pFile->hShared){
1321318507b7Smistachkin     pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared,
132272aead81Sdrh              FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock));
132372aead81Sdrh     /* If mapping failed, close the shared memory handle and erase it */
132472aead81Sdrh     if (!pFile->shared){
1325318507b7Smistachkin       pFile->lastErrno = osGetLastError();
13262aef997cSmistachkin       winLogError(SQLITE_ERROR, pFile->lastErrno,
13272aef997cSmistachkin                "winceCreateLock2", zFilename);
1328318507b7Smistachkin       osCloseHandle(pFile->hShared);
132972aead81Sdrh       pFile->hShared = NULL;
133072aead81Sdrh     }
133172aead81Sdrh   }
133272aead81Sdrh 
133372aead81Sdrh   /* If shared memory could not be created, then close the mutex and fail */
133472aead81Sdrh   if (pFile->hShared == NULL){
133572aead81Sdrh     winceMutexRelease(pFile->hMutex);
1336318507b7Smistachkin     osCloseHandle(pFile->hMutex);
133772aead81Sdrh     pFile->hMutex = NULL;
133872aead81Sdrh     return FALSE;
133972aead81Sdrh   }
134072aead81Sdrh 
134172aead81Sdrh   /* Initialize the shared memory if we're supposed to */
134272aead81Sdrh   if (bInit) {
1343318507b7Smistachkin     memset(pFile->shared, 0, sizeof(winceLock));
134472aead81Sdrh   }
134572aead81Sdrh 
134672aead81Sdrh   winceMutexRelease(pFile->hMutex);
134772aead81Sdrh   return TRUE;
134872aead81Sdrh }
134972aead81Sdrh 
135072aead81Sdrh /*
135172aead81Sdrh ** Destroy the part of winFile that deals with wince locks
135272aead81Sdrh */
135372aead81Sdrh static void winceDestroyLock(winFile *pFile){
135472aead81Sdrh   if (pFile->hMutex){
135572aead81Sdrh     /* Acquire the mutex */
135672aead81Sdrh     winceMutexAcquire(pFile->hMutex);
135772aead81Sdrh 
135872aead81Sdrh     /* The following blocks should probably assert in debug mode, but they
135972aead81Sdrh        are to cleanup in case any locks remained open */
136072aead81Sdrh     if (pFile->local.nReaders){
136172aead81Sdrh       pFile->shared->nReaders --;
136272aead81Sdrh     }
136372aead81Sdrh     if (pFile->local.bReserved){
136472aead81Sdrh       pFile->shared->bReserved = FALSE;
136572aead81Sdrh     }
136672aead81Sdrh     if (pFile->local.bPending){
136772aead81Sdrh       pFile->shared->bPending = FALSE;
136872aead81Sdrh     }
136972aead81Sdrh     if (pFile->local.bExclusive){
137072aead81Sdrh       pFile->shared->bExclusive = FALSE;
137172aead81Sdrh     }
137272aead81Sdrh 
137372aead81Sdrh     /* De-reference and close our copy of the shared memory handle */
1374318507b7Smistachkin     osUnmapViewOfFile(pFile->shared);
1375318507b7Smistachkin     osCloseHandle(pFile->hShared);
137672aead81Sdrh 
137772aead81Sdrh     /* Done with the mutex */
137872aead81Sdrh     winceMutexRelease(pFile->hMutex);
1379318507b7Smistachkin     osCloseHandle(pFile->hMutex);
138072aead81Sdrh     pFile->hMutex = NULL;
138172aead81Sdrh   }
138272aead81Sdrh }
138372aead81Sdrh 
138472aead81Sdrh /*
1385318507b7Smistachkin ** An implementation of the LockFile() API of Windows for CE
138672aead81Sdrh */
138772aead81Sdrh static BOOL winceLockFile(
138872aead81Sdrh   HANDLE *phFile,
138972aead81Sdrh   DWORD dwFileOffsetLow,
139072aead81Sdrh   DWORD dwFileOffsetHigh,
139172aead81Sdrh   DWORD nNumberOfBytesToLockLow,
139272aead81Sdrh   DWORD nNumberOfBytesToLockHigh
139372aead81Sdrh ){
139472aead81Sdrh   winFile *pFile = HANDLE_TO_WINFILE(phFile);
139572aead81Sdrh   BOOL bReturn = FALSE;
139672aead81Sdrh 
1397d87873d1Sshane   UNUSED_PARAMETER(dwFileOffsetHigh);
1398d87873d1Sshane   UNUSED_PARAMETER(nNumberOfBytesToLockHigh);
1399d87873d1Sshane 
140072aead81Sdrh   if (!pFile->hMutex) return TRUE;
140172aead81Sdrh   winceMutexAcquire(pFile->hMutex);
140272aead81Sdrh 
140372aead81Sdrh   /* Wanting an exclusive lock? */
140411bb41f8Sshane   if (dwFileOffsetLow == (DWORD)SHARED_FIRST
140511bb41f8Sshane        && nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){
140672aead81Sdrh     if (pFile->shared->nReaders == 0 && pFile->shared->bExclusive == 0){
140772aead81Sdrh        pFile->shared->bExclusive = TRUE;
140872aead81Sdrh        pFile->local.bExclusive = TRUE;
140972aead81Sdrh        bReturn = TRUE;
141072aead81Sdrh     }
141172aead81Sdrh   }
141272aead81Sdrh 
141372aead81Sdrh   /* Want a read-only lock? */
141411bb41f8Sshane   else if (dwFileOffsetLow == (DWORD)SHARED_FIRST &&
141572aead81Sdrh            nNumberOfBytesToLockLow == 1){
141672aead81Sdrh     if (pFile->shared->bExclusive == 0){
141772aead81Sdrh       pFile->local.nReaders ++;
141872aead81Sdrh       if (pFile->local.nReaders == 1){
141972aead81Sdrh         pFile->shared->nReaders ++;
142072aead81Sdrh       }
142172aead81Sdrh       bReturn = TRUE;
142272aead81Sdrh     }
142372aead81Sdrh   }
142472aead81Sdrh 
142572aead81Sdrh   /* Want a pending lock? */
142611bb41f8Sshane   else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToLockLow == 1){
142772aead81Sdrh     /* If no pending lock has been acquired, then acquire it */
142872aead81Sdrh     if (pFile->shared->bPending == 0) {
142972aead81Sdrh       pFile->shared->bPending = TRUE;
143072aead81Sdrh       pFile->local.bPending = TRUE;
143172aead81Sdrh       bReturn = TRUE;
143272aead81Sdrh     }
143372aead81Sdrh   }
1434338ea3c1Sshane 
143572aead81Sdrh   /* Want a reserved lock? */
143611bb41f8Sshane   else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToLockLow == 1){
143772aead81Sdrh     if (pFile->shared->bReserved == 0) {
143872aead81Sdrh       pFile->shared->bReserved = TRUE;
143972aead81Sdrh       pFile->local.bReserved = TRUE;
144072aead81Sdrh       bReturn = TRUE;
144172aead81Sdrh     }
144272aead81Sdrh   }
144372aead81Sdrh 
144472aead81Sdrh   winceMutexRelease(pFile->hMutex);
144572aead81Sdrh   return bReturn;
144672aead81Sdrh }
144772aead81Sdrh 
144872aead81Sdrh /*
1449318507b7Smistachkin ** An implementation of the UnlockFile API of Windows for CE
145072aead81Sdrh */
145172aead81Sdrh static BOOL winceUnlockFile(
145272aead81Sdrh   HANDLE *phFile,
145372aead81Sdrh   DWORD dwFileOffsetLow,
145472aead81Sdrh   DWORD dwFileOffsetHigh,
145572aead81Sdrh   DWORD nNumberOfBytesToUnlockLow,
145672aead81Sdrh   DWORD nNumberOfBytesToUnlockHigh
145772aead81Sdrh ){
145872aead81Sdrh   winFile *pFile = HANDLE_TO_WINFILE(phFile);
145972aead81Sdrh   BOOL bReturn = FALSE;
146072aead81Sdrh 
1461d87873d1Sshane   UNUSED_PARAMETER(dwFileOffsetHigh);
1462d87873d1Sshane   UNUSED_PARAMETER(nNumberOfBytesToUnlockHigh);
1463d87873d1Sshane 
146472aead81Sdrh   if (!pFile->hMutex) return TRUE;
146572aead81Sdrh   winceMutexAcquire(pFile->hMutex);
146672aead81Sdrh 
146772aead81Sdrh   /* Releasing a reader lock or an exclusive lock */
146811bb41f8Sshane   if (dwFileOffsetLow == (DWORD)SHARED_FIRST){
146972aead81Sdrh     /* Did we have an exclusive lock? */
147072aead81Sdrh     if (pFile->local.bExclusive){
147111bb41f8Sshane       assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE);
147272aead81Sdrh       pFile->local.bExclusive = FALSE;
147372aead81Sdrh       pFile->shared->bExclusive = FALSE;
147472aead81Sdrh       bReturn = TRUE;
147572aead81Sdrh     }
147672aead81Sdrh 
147772aead81Sdrh     /* Did we just have a reader lock? */
147872aead81Sdrh     else if (pFile->local.nReaders){
147911bb41f8Sshane       assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE || nNumberOfBytesToUnlockLow == 1);
148072aead81Sdrh       pFile->local.nReaders --;
148172aead81Sdrh       if (pFile->local.nReaders == 0)
148272aead81Sdrh       {
148372aead81Sdrh         pFile->shared->nReaders --;
148472aead81Sdrh       }
148572aead81Sdrh       bReturn = TRUE;
148672aead81Sdrh     }
148772aead81Sdrh   }
148872aead81Sdrh 
148972aead81Sdrh   /* Releasing a pending lock */
149011bb41f8Sshane   else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToUnlockLow == 1){
149172aead81Sdrh     if (pFile->local.bPending){
149272aead81Sdrh       pFile->local.bPending = FALSE;
149372aead81Sdrh       pFile->shared->bPending = FALSE;
149472aead81Sdrh       bReturn = TRUE;
149572aead81Sdrh     }
149672aead81Sdrh   }
149772aead81Sdrh   /* Releasing a reserved lock */
149811bb41f8Sshane   else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1){
149972aead81Sdrh     if (pFile->local.bReserved) {
150072aead81Sdrh       pFile->local.bReserved = FALSE;
150172aead81Sdrh       pFile->shared->bReserved = FALSE;
150272aead81Sdrh       bReturn = TRUE;
150372aead81Sdrh     }
150472aead81Sdrh   }
150572aead81Sdrh 
150672aead81Sdrh   winceMutexRelease(pFile->hMutex);
150772aead81Sdrh   return bReturn;
150872aead81Sdrh }
150972aead81Sdrh 
151072aead81Sdrh /*
1511318507b7Smistachkin ** An implementation of the LockFileEx() API of Windows for CE
151272aead81Sdrh */
151372aead81Sdrh static BOOL winceLockFileEx(
151472aead81Sdrh   HANDLE *phFile,
151572aead81Sdrh   DWORD dwFlags,
151672aead81Sdrh   DWORD dwReserved,
151772aead81Sdrh   DWORD nNumberOfBytesToLockLow,
151872aead81Sdrh   DWORD nNumberOfBytesToLockHigh,
151972aead81Sdrh   LPOVERLAPPED lpOverlapped
152072aead81Sdrh ){
1521d87873d1Sshane   UNUSED_PARAMETER(dwReserved);
1522d87873d1Sshane   UNUSED_PARAMETER(nNumberOfBytesToLockHigh);
1523d87873d1Sshane 
152472aead81Sdrh   /* If the caller wants a shared read lock, forward this call
152572aead81Sdrh   ** to winceLockFile */
152611bb41f8Sshane   if (lpOverlapped->Offset == (DWORD)SHARED_FIRST &&
152772aead81Sdrh       dwFlags == 1 &&
152811bb41f8Sshane       nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){
152972aead81Sdrh     return winceLockFile(phFile, SHARED_FIRST, 0, 1, 0);
153072aead81Sdrh   }
153172aead81Sdrh   return FALSE;
153272aead81Sdrh }
153372aead81Sdrh /*
153472aead81Sdrh ** End of the special code for wince
153572aead81Sdrh *****************************************************************************/
153629bafeabSdanielk1977 #endif /* SQLITE_OS_WINCE */
1537c0929987Sdrh 
1538153c62c4Sdrh /*****************************************************************************
1539153c62c4Sdrh ** The next group of routines implement the I/O methods specified
1540153c62c4Sdrh ** by the sqlite3_io_methods object.
1541153c62c4Sdrh ******************************************************************************/
1542bbd42a6dSdrh 
1543bbd42a6dSdrh /*
1544318507b7Smistachkin ** Some Microsoft compilers lack this definition.
1545502019c8Sdan */
1546502019c8Sdan #ifndef INVALID_SET_FILE_POINTER
1547502019c8Sdan # define INVALID_SET_FILE_POINTER ((DWORD)-1)
1548502019c8Sdan #endif
1549502019c8Sdan 
1550502019c8Sdan /*
1551502019c8Sdan ** Move the current position of the file handle passed as the first
1552502019c8Sdan ** argument to offset iOffset within the file. If successful, return 0.
1553502019c8Sdan ** Otherwise, set pFile->lastErrno and return non-zero.
1554502019c8Sdan */
1555502019c8Sdan static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
1556502019c8Sdan   LONG upperBits;                 /* Most sig. 32 bits of new offset */
1557502019c8Sdan   LONG lowerBits;                 /* Least sig. 32 bits of new offset */
1558502019c8Sdan   DWORD dwRet;                    /* Value returned by SetFilePointer() */
1559d1ef9b6dSmistachkin   DWORD lastErrno;                /* Value returned by GetLastError() */
1560502019c8Sdan 
1561502019c8Sdan   upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
1562502019c8Sdan   lowerBits = (LONG)(iOffset & 0xffffffff);
1563502019c8Sdan 
1564502019c8Sdan   /* API oddity: If successful, SetFilePointer() returns a dword
1565502019c8Sdan   ** containing the lower 32-bits of the new file-offset. Or, if it fails,
1566502019c8Sdan   ** it returns INVALID_SET_FILE_POINTER. However according to MSDN,
1567502019c8Sdan   ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine
1568502019c8Sdan   ** whether an error has actually occured, it is also necessary to call
1569502019c8Sdan   ** GetLastError().
1570502019c8Sdan   */
1571318507b7Smistachkin   dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
1572d1ef9b6dSmistachkin 
1573d1ef9b6dSmistachkin   if( (dwRet==INVALID_SET_FILE_POINTER
1574d1ef9b6dSmistachkin       && ((lastErrno = osGetLastError())!=NO_ERROR)) ){
1575d1ef9b6dSmistachkin     pFile->lastErrno = lastErrno;
15762aef997cSmistachkin     winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
15772aef997cSmistachkin              "seekWinFile", pFile->zPath);
1578502019c8Sdan     return 1;
1579502019c8Sdan   }
1580502019c8Sdan 
1581502019c8Sdan   return 0;
1582502019c8Sdan }
1583502019c8Sdan 
1584502019c8Sdan /*
1585bbd42a6dSdrh ** Close a file.
158659e63a6bSdrh **
158759e63a6bSdrh ** It is reported that an attempt to close a handle might sometimes
1588318507b7Smistachkin ** fail.  This is a very unreasonable result, but Windows is notorious
158959e63a6bSdrh ** for being unreasonable so I do not doubt that it might happen.  If
159059e63a6bSdrh ** the close fails, we pause for 100 milliseconds and try again.  As
159159e63a6bSdrh ** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before
159259e63a6bSdrh ** giving up and returning an error.
1593bbd42a6dSdrh */
159459e63a6bSdrh #define MX_CLOSE_ATTEMPT 3
1595153c62c4Sdrh static int winClose(sqlite3_file *id){
1596eb4fa52aSdrh   int rc, cnt = 0;
1597153c62c4Sdrh   winFile *pFile = (winFile*)id;
159850daafc7Sshane 
159950daafc7Sshane   assert( id!=0 );
160083235214Sdrh   assert( pFile->pShm==0 );
1601308c2a5cSdrh   OSTRACE(("CLOSE %d\n", pFile->h));
1602eb4fa52aSdrh   do{
1603318507b7Smistachkin     rc = osCloseHandle(pFile->h);
1604e2ad9317Sshaneh     /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */
1605318507b7Smistachkin   }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (osSleep(100), 1) );
160629bafeabSdanielk1977 #if SQLITE_OS_WINCE
1607d641d511Sdrh #define WINCE_DELETION_ATTEMPTS 3
160872aead81Sdrh   winceDestroyLock(pFile);
16097229ed43Sdrh   if( pFile->zDeleteOnClose ){
1610d641d511Sdrh     int cnt = 0;
1611d641d511Sdrh     while(
1612318507b7Smistachkin            osDeleteFileW(pFile->zDeleteOnClose)==0
1613318507b7Smistachkin         && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff
1614d641d511Sdrh         && cnt++ < WINCE_DELETION_ATTEMPTS
1615d641d511Sdrh     ){
1616318507b7Smistachkin        osSleep(100);  /* Wait a little before trying again */
1617d641d511Sdrh     }
16185f075388Smistachkin     sqlite3_free(pFile->zDeleteOnClose);
16197229ed43Sdrh   }
1620cc78fea4Sdrh #endif
162104882a9eSshaneh   OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed"));
1622bbd42a6dSdrh   OpenCounter(-1);
162350990dbbSdrh   return rc ? SQLITE_OK
1624318507b7Smistachkin             : winLogError(SQLITE_IOERR_CLOSE, osGetLastError(),
16252aef997cSmistachkin                           "winClose", pFile->zPath);
1626bbd42a6dSdrh }
1627bbd42a6dSdrh 
1628bbd42a6dSdrh /*
1629bbd42a6dSdrh ** Read data from a file into a buffer.  Return SQLITE_OK if all
1630bbd42a6dSdrh ** bytes were read successfully and SQLITE_IOERR if anything goes
1631bbd42a6dSdrh ** wrong.
1632bbd42a6dSdrh */
1633153c62c4Sdrh static int winRead(
1634153c62c4Sdrh   sqlite3_file *id,          /* File to read from */
1635153c62c4Sdrh   void *pBuf,                /* Write content into this buffer */
1636153c62c4Sdrh   int amt,                   /* Number of bytes to read */
1637153c62c4Sdrh   sqlite3_int64 offset       /* Begin reading at this offset */
1638153c62c4Sdrh ){
1639502019c8Sdan   winFile *pFile = (winFile*)id;  /* file handle */
1640502019c8Sdan   DWORD nRead;                    /* Number of bytes actually read from file */
16415d9ef0a6Sdrh   int nRetry = 0;                 /* Number of retrys */
164250daafc7Sshane 
16439cbe6352Sdrh   assert( id!=0 );
16449cce7109Sdrh   SimulateIOError(return SQLITE_IOERR_READ);
1645308c2a5cSdrh   OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype));
1646502019c8Sdan 
1647502019c8Sdan   if( seekWinFile(pFile, offset) ){
1648153c62c4Sdrh     return SQLITE_FULL;
1649153c62c4Sdrh   }
1650318507b7Smistachkin   while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
1651d1ef9b6dSmistachkin     DWORD lastErrno;
1652d1ef9b6dSmistachkin     if( retryIoerr(&nRetry, &lastErrno) ) continue;
1653d1ef9b6dSmistachkin     pFile->lastErrno = lastErrno;
16542aef997cSmistachkin     return winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
16552aef997cSmistachkin              "winRead", pFile->zPath);
1656bbd42a6dSdrh   }
1657a32ad843Sdrh   logIoerr(nRetry);
1658502019c8Sdan   if( nRead<(DWORD)amt ){
16594c17c3fbSdrh     /* Unread parts of the buffer must be zero-filled */
1660502019c8Sdan     memset(&((char*)pBuf)[nRead], 0, amt-nRead);
1661551b7736Sdrh     return SQLITE_IOERR_SHORT_READ;
1662bbd42a6dSdrh   }
1663502019c8Sdan 
1664502019c8Sdan   return SQLITE_OK;
1665bbd42a6dSdrh }
1666bbd42a6dSdrh 
1667bbd42a6dSdrh /*
1668bbd42a6dSdrh ** Write data from a buffer into a file.  Return SQLITE_OK on success
1669bbd42a6dSdrh ** or some other error code on failure.
1670bbd42a6dSdrh */
1671153c62c4Sdrh static int winWrite(
1672153c62c4Sdrh   sqlite3_file *id,               /* File to write into */
1673153c62c4Sdrh   const void *pBuf,               /* The bytes to be written */
1674153c62c4Sdrh   int amt,                        /* Number of bytes to write */
1675153c62c4Sdrh   sqlite3_int64 offset            /* Offset into the file to begin writing at */
1676153c62c4Sdrh ){
1677502019c8Sdan   int rc;                         /* True if error has occured, else false */
1678502019c8Sdan   winFile *pFile = (winFile*)id;  /* File handle */
1679a32ad843Sdrh   int nRetry = 0;                 /* Number of retries */
168050daafc7Sshane 
1681502019c8Sdan   assert( amt>0 );
1682502019c8Sdan   assert( pFile );
1683153c62c4Sdrh   SimulateIOError(return SQLITE_IOERR_WRITE);
16845968593bSdrh   SimulateDiskfullError(return SQLITE_FULL);
1685502019c8Sdan 
1686308c2a5cSdrh   OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype));
1687502019c8Sdan 
1688502019c8Sdan   rc = seekWinFile(pFile, offset);
1689502019c8Sdan   if( rc==0 ){
1690502019c8Sdan     u8 *aRem = (u8 *)pBuf;        /* Data yet to be written */
1691502019c8Sdan     int nRem = amt;               /* Number of bytes yet to be written */
1692502019c8Sdan     DWORD nWrite;                 /* Bytes written by each WriteFile() call */
1693d1ef9b6dSmistachkin     DWORD lastErrno = NO_ERROR;   /* Value returned by GetLastError() */
1694502019c8Sdan 
16955d9ef0a6Sdrh     while( nRem>0 ){
1696318507b7Smistachkin       if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
1697d1ef9b6dSmistachkin         if( retryIoerr(&nRetry, &lastErrno) ) continue;
16985d9ef0a6Sdrh         break;
16995d9ef0a6Sdrh       }
17005d9ef0a6Sdrh       if( nWrite<=0 ) break;
1701502019c8Sdan       aRem += nWrite;
1702502019c8Sdan       nRem -= nWrite;
1703133ce560Sshaneh     }
1704502019c8Sdan     if( nRem>0 ){
1705d1ef9b6dSmistachkin       pFile->lastErrno = lastErrno;
1706502019c8Sdan       rc = 1;
1707502019c8Sdan     }
1708502019c8Sdan   }
1709502019c8Sdan 
1710502019c8Sdan   if( rc ){
1711eeb5d8aaSshaneh     if(   ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL )
1712eeb5d8aaSshaneh        || ( pFile->lastErrno==ERROR_DISK_FULL )){
1713bbd42a6dSdrh       return SQLITE_FULL;
1714133ce560Sshaneh     }
17152aef997cSmistachkin     return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno,
17162aef997cSmistachkin              "winWrite", pFile->zPath);
1717a32ad843Sdrh   }else{
1718a32ad843Sdrh     logIoerr(nRetry);
1719bbd42a6dSdrh   }
1720bbd42a6dSdrh   return SQLITE_OK;
1721bbd42a6dSdrh }
1722bbd42a6dSdrh 
1723bbd42a6dSdrh /*
1724153c62c4Sdrh ** Truncate an open file to a specified size
1725bbdc2b94Sdrh */
1726c51250a5Sdrh static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
1727502019c8Sdan   winFile *pFile = (winFile*)id;  /* File handle object */
1728502019c8Sdan   int rc = SQLITE_OK;             /* Return code for this function */
172950daafc7Sshane 
1730502019c8Sdan   assert( pFile );
1731502019c8Sdan 
1732308c2a5cSdrh   OSTRACE(("TRUNCATE %d %lld\n", pFile->h, nByte));
1733153c62c4Sdrh   SimulateIOError(return SQLITE_IOERR_TRUNCATE);
1734502019c8Sdan 
1735502019c8Sdan   /* If the user has configured a chunk-size for this file, truncate the
1736502019c8Sdan   ** file so that it consists of an integer number of chunks (i.e. the
1737502019c8Sdan   ** actual file size after the operation may be larger than the requested
1738502019c8Sdan   ** size).
1739502019c8Sdan   */
1740d589a544Smistachkin   if( pFile->szChunk>0 ){
1741502019c8Sdan     nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
1742502019c8Sdan   }
1743502019c8Sdan 
1744502019c8Sdan   /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
1745502019c8Sdan   if( seekWinFile(pFile, nByte) ){
17462aef997cSmistachkin     rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
17472aef997cSmistachkin              "winTruncate1", pFile->zPath);
1748318507b7Smistachkin   }else if( 0==osSetEndOfFile(pFile->h) ){
1749318507b7Smistachkin     pFile->lastErrno = osGetLastError();
17502aef997cSmistachkin     rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
17512aef997cSmistachkin              "winTruncate2", pFile->zPath);
175250daafc7Sshane   }
1753502019c8Sdan 
1754502019c8Sdan   OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok"));
175504882a9eSshaneh   return rc;
175650daafc7Sshane }
1757bbd42a6dSdrh 
1758dec6fae9Sdrh #ifdef SQLITE_TEST
1759dec6fae9Sdrh /*
1760dec6fae9Sdrh ** Count the number of fullsyncs and normal syncs.  This is used to test
1761dec6fae9Sdrh ** that syncs and fullsyncs are occuring at the right times.
1762dec6fae9Sdrh */
1763dec6fae9Sdrh int sqlite3_sync_count = 0;
1764dec6fae9Sdrh int sqlite3_fullsync_count = 0;
1765dec6fae9Sdrh #endif
1766dec6fae9Sdrh 
1767bbd42a6dSdrh /*
1768bbd42a6dSdrh ** Make sure all writes to a particular file are committed to disk.
1769bbd42a6dSdrh */
1770153c62c4Sdrh static int winSync(sqlite3_file *id, int flags){
1771c377f310Smistachkin #ifndef SQLITE_NO_SYNC
1772c377f310Smistachkin   /*
1773c377f310Smistachkin   ** Used only when SQLITE_NO_SYNC is not defined.
1774c377f310Smistachkin    */
17759dd6e080Sshaneh   BOOL rc;
1776c377f310Smistachkin #endif
1777c377f310Smistachkin #if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || \
1778c377f310Smistachkin     (defined(SQLITE_TEST) && defined(SQLITE_DEBUG))
1779c377f310Smistachkin   /*
1780c377f310Smistachkin   ** Used when SQLITE_NO_SYNC is not defined and by the assert() and/or
1781c377f310Smistachkin   ** OSTRACE() macros.
1782c377f310Smistachkin    */
1783c377f310Smistachkin   winFile *pFile = (winFile*)id;
178418e526c1Sshane #else
178518e526c1Sshane   UNUSED_PARAMETER(id);
178618e526c1Sshane #endif
1787e2ad9317Sshaneh 
1788e2ad9317Sshaneh   assert( pFile );
1789e2ad9317Sshaneh   /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */
1790e2ad9317Sshaneh   assert((flags&0x0F)==SQLITE_SYNC_NORMAL
1791e2ad9317Sshaneh       || (flags&0x0F)==SQLITE_SYNC_FULL
1792e2ad9317Sshaneh   );
1793e2ad9317Sshaneh 
1794e2ad9317Sshaneh   OSTRACE(("SYNC %d lock=%d\n", pFile->h, pFile->locktype));
1795e2ad9317Sshaneh 
1796e2ad9317Sshaneh   /* Unix cannot, but some systems may return SQLITE_FULL from here. This
1797e2ad9317Sshaneh   ** line is to test that doing so does not cause any problems.
1798e2ad9317Sshaneh   */
1799e2ad9317Sshaneh   SimulateDiskfullError( return SQLITE_FULL );
18009dd6e080Sshaneh 
18019dd6e080Sshaneh #ifndef SQLITE_TEST
18029dd6e080Sshaneh   UNUSED_PARAMETER(flags);
18039dd6e080Sshaneh #else
18049dd6e080Sshaneh   if( (flags&0x0F)==SQLITE_SYNC_FULL ){
18059dd6e080Sshaneh     sqlite3_fullsync_count++;
18069dd6e080Sshaneh   }
18079dd6e080Sshaneh   sqlite3_sync_count++;
18089dd6e080Sshaneh #endif
1809e2ad9317Sshaneh 
181084ca3837Sshane   /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
181184ca3837Sshane   ** no-op
181284ca3837Sshane   */
181384ca3837Sshane #ifdef SQLITE_NO_SYNC
181484ca3837Sshane   return SQLITE_OK;
181584ca3837Sshane #else
1816318507b7Smistachkin   rc = osFlushFileBuffers(pFile->h);
18179dd6e080Sshaneh   SimulateIOError( rc=FALSE );
18189dd6e080Sshaneh   if( rc ){
1819bbd42a6dSdrh     return SQLITE_OK;
1820bbd42a6dSdrh   }else{
1821318507b7Smistachkin     pFile->lastErrno = osGetLastError();
18222aef997cSmistachkin     return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno,
18232aef997cSmistachkin              "winSync", pFile->zPath);
1824bbd42a6dSdrh   }
182584ca3837Sshane #endif
1826bbd42a6dSdrh }
1827bbd42a6dSdrh 
1828bbd42a6dSdrh /*
1829bbd42a6dSdrh ** Determine the current size of a file in bytes
1830bbd42a6dSdrh */
1831153c62c4Sdrh static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
183250daafc7Sshane   DWORD upperBits;
183350daafc7Sshane   DWORD lowerBits;
1834153c62c4Sdrh   winFile *pFile = (winFile*)id;
1835d1ef9b6dSmistachkin   DWORD lastErrno;
183650daafc7Sshane 
183750daafc7Sshane   assert( id!=0 );
18389cce7109Sdrh   SimulateIOError(return SQLITE_IOERR_FSTAT);
1839318507b7Smistachkin   lowerBits = osGetFileSize(pFile->h, &upperBits);
18409db299fbSshane   if(   (lowerBits == INVALID_FILE_SIZE)
1841d1ef9b6dSmistachkin      && ((lastErrno = osGetLastError())!=NO_ERROR) )
18429db299fbSshane   {
1843d1ef9b6dSmistachkin     pFile->lastErrno = lastErrno;
18442aef997cSmistachkin     return winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno,
18452aef997cSmistachkin              "winFileSize", pFile->zPath);
18469db299fbSshane   }
1847153c62c4Sdrh   *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits;
1848bbd42a6dSdrh   return SQLITE_OK;
1849bbd42a6dSdrh }
1850bbd42a6dSdrh 
1851bbd42a6dSdrh /*
1852602bbd32Sdrh ** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems.
1853602bbd32Sdrh */
1854602bbd32Sdrh #ifndef LOCKFILE_FAIL_IMMEDIATELY
1855602bbd32Sdrh # define LOCKFILE_FAIL_IMMEDIATELY 1
1856602bbd32Sdrh #endif
1857602bbd32Sdrh 
1858602bbd32Sdrh /*
18599c105bb9Sdrh ** Acquire a reader lock.
186051c6d963Sdrh ** Different API routines are called depending on whether or not this
18616c3c1a09Smistachkin ** is Win9x or WinNT.
186251c6d963Sdrh */
1863153c62c4Sdrh static int getReadLock(winFile *pFile){
186451c6d963Sdrh   int res;
186551c6d963Sdrh   if( isNT() ){
186651c6d963Sdrh     OVERLAPPED ovlp;
18679c105bb9Sdrh     ovlp.Offset = SHARED_FIRST;
186851c6d963Sdrh     ovlp.OffsetHigh = 0;
186951c6d963Sdrh     ovlp.hEvent = 0;
1870318507b7Smistachkin     res = osLockFileEx(pFile->h, LOCKFILE_FAIL_IMMEDIATELY,
1871153c62c4Sdrh                        0, SHARED_SIZE, 0, &ovlp);
1872891adeacSshane /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
1873891adeacSshane */
1874891adeacSshane #if SQLITE_OS_WINCE==0
187551c6d963Sdrh   }else{
18769c105bb9Sdrh     int lk;
18772fa1868fSdrh     sqlite3_randomness(sizeof(lk), &lk);
18781bd10f8aSdrh     pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1));
1879318507b7Smistachkin     res = osLockFile(pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
1880891adeacSshane #endif
188151c6d963Sdrh   }
18829db299fbSshane   if( res == 0 ){
1883318507b7Smistachkin     pFile->lastErrno = osGetLastError();
188450990dbbSdrh     /* No need to log a failure to lock */
18859db299fbSshane   }
188651c6d963Sdrh   return res;
188751c6d963Sdrh }
188851c6d963Sdrh 
188951c6d963Sdrh /*
189051c6d963Sdrh ** Undo a readlock
189151c6d963Sdrh */
1892054889ecSdrh static int unlockReadLock(winFile *pFile){
189351c6d963Sdrh   int res;
1894d1ef9b6dSmistachkin   DWORD lastErrno;
189551c6d963Sdrh   if( isNT() ){
1896318507b7Smistachkin     res = osUnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
1897891adeacSshane /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
1898891adeacSshane */
1899891adeacSshane #if SQLITE_OS_WINCE==0
190051c6d963Sdrh   }else{
1901318507b7Smistachkin     res = osUnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0);
1902891adeacSshane #endif
190351c6d963Sdrh   }
1904d1ef9b6dSmistachkin   if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){
1905d1ef9b6dSmistachkin     pFile->lastErrno = lastErrno;
19062aef997cSmistachkin     winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno,
19072aef997cSmistachkin              "unlockReadLock", pFile->zPath);
19089db299fbSshane   }
190951c6d963Sdrh   return res;
191051c6d963Sdrh }
191151c6d963Sdrh 
19129a09a3caStpoindex /*
1913b3e04346Sdrh ** Lock the file with the lock specified by parameter locktype - one
1914b3e04346Sdrh ** of the following:
1915b3e04346Sdrh **
1916b3e04346Sdrh **     (1) SHARED_LOCK
1917b3e04346Sdrh **     (2) RESERVED_LOCK
1918b3e04346Sdrh **     (3) PENDING_LOCK
1919b3e04346Sdrh **     (4) EXCLUSIVE_LOCK
1920b3e04346Sdrh **
1921b3e04346Sdrh ** Sometimes when requesting one lock state, additional lock states
1922b3e04346Sdrh ** are inserted in between.  The locking might fail on one of the later
1923b3e04346Sdrh ** transitions leaving the lock state different from what it started but
1924b3e04346Sdrh ** still short of its goal.  The following chart shows the allowed
1925b3e04346Sdrh ** transitions and the inserted intermediate states:
1926b3e04346Sdrh **
1927b3e04346Sdrh **    UNLOCKED -> SHARED
1928b3e04346Sdrh **    SHARED -> RESERVED
1929b3e04346Sdrh **    SHARED -> (PENDING) -> EXCLUSIVE
1930b3e04346Sdrh **    RESERVED -> (PENDING) -> EXCLUSIVE
1931b3e04346Sdrh **    PENDING -> EXCLUSIVE
1932b3e04346Sdrh **
19339c06c953Sdrh ** This routine will only increase a lock.  The winUnlock() routine
1934b3e04346Sdrh ** erases all locks at once and returns us immediately to locking level 0.
1935b3e04346Sdrh ** It is not possible to lower the locking level one step at a time.  You
1936b3e04346Sdrh ** must go straight to locking level 0.
193751c6d963Sdrh */
1938153c62c4Sdrh static int winLock(sqlite3_file *id, int locktype){
193951c6d963Sdrh   int rc = SQLITE_OK;    /* Return code from subroutines */
1940318507b7Smistachkin   int res = 1;           /* Result of a Windows lock call */
1941153c62c4Sdrh   int newLocktype;       /* Set pFile->locktype to this value before exiting */
1942e54ca3feSdrh   int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
1943054889ecSdrh   winFile *pFile = (winFile*)id;
1944d1ef9b6dSmistachkin   DWORD lastErrno = NO_ERROR;
194551c6d963Sdrh 
194650daafc7Sshane   assert( id!=0 );
1947308c2a5cSdrh   OSTRACE(("LOCK %d %d was %d(%d)\n",
1948308c2a5cSdrh            pFile->h, locktype, pFile->locktype, pFile->sharedLockByte));
194951c6d963Sdrh 
195051c6d963Sdrh   /* If there is already a lock of this type or more restrictive on the
195151c6d963Sdrh   ** OsFile, do nothing. Don't use the end_lock: exit path, as
195251c6d963Sdrh   ** sqlite3OsEnterMutex() hasn't been called yet.
195351c6d963Sdrh   */
1954054889ecSdrh   if( pFile->locktype>=locktype ){
19552a02e339Sdanielk1977     return SQLITE_OK;
19562a02e339Sdanielk1977   }
19572a02e339Sdanielk1977 
1958b3e04346Sdrh   /* Make sure the locking sequence is correct
1959b3e04346Sdrh   */
1960054889ecSdrh   assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
1961b3e04346Sdrh   assert( locktype!=PENDING_LOCK );
1962054889ecSdrh   assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
1963b3e04346Sdrh 
196451c6d963Sdrh   /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
196551c6d963Sdrh   ** a SHARED lock.  If we are acquiring a SHARED lock, the acquisition of
196651c6d963Sdrh   ** the PENDING_LOCK byte is temporary.
196751c6d963Sdrh   */
1968054889ecSdrh   newLocktype = pFile->locktype;
19699db299fbSshane   if(   (pFile->locktype==NO_LOCK)
19709db299fbSshane      || (   (locktype==EXCLUSIVE_LOCK)
19719db299fbSshane          && (pFile->locktype==RESERVED_LOCK))
1972e54ca3feSdrh   ){
1973b3e04346Sdrh     int cnt = 3;
1974318507b7Smistachkin     while( cnt-->0 && (res = osLockFile(pFile->h, PENDING_BYTE, 0, 1, 0))==0 ){
1975d6ca4b9fSdrh       /* Try 3 times to get the pending lock.  This is needed to work
1976318507b7Smistachkin       ** around problems caused by indexing and/or anti-virus software on
1977318507b7Smistachkin       ** Windows systems.
1978d6ca4b9fSdrh       ** If you are using this code as a model for alternative VFSes, do not
1979318507b7Smistachkin       ** copy this retry logic.  It is a hack intended for Windows only.
198051c6d963Sdrh       */
1981308c2a5cSdrh       OSTRACE(("could not get a PENDING lock. cnt=%d\n", cnt));
1982318507b7Smistachkin       if( cnt ) osSleep(1);
198351c6d963Sdrh     }
1984e54ca3feSdrh     gotPendingLock = res;
19859db299fbSshane     if( !res ){
1986d1ef9b6dSmistachkin       lastErrno = osGetLastError();
19879db299fbSshane     }
19882a02e339Sdanielk1977   }
19892a02e339Sdanielk1977 
199051c6d963Sdrh   /* Acquire a shared lock
1991bbd42a6dSdrh   */
1992b3e04346Sdrh   if( locktype==SHARED_LOCK && res ){
1993054889ecSdrh     assert( pFile->locktype==NO_LOCK );
1994054889ecSdrh     res = getReadLock(pFile);
1995e54ca3feSdrh     if( res ){
1996e54ca3feSdrh       newLocktype = SHARED_LOCK;
19979db299fbSshane     }else{
1998d1ef9b6dSmistachkin       lastErrno = osGetLastError();
1999bbd42a6dSdrh     }
2000bbd42a6dSdrh   }
2001bbd42a6dSdrh 
200251c6d963Sdrh   /* Acquire a RESERVED lock
2003bbd42a6dSdrh   */
2004b3e04346Sdrh   if( locktype==RESERVED_LOCK && res ){
2005054889ecSdrh     assert( pFile->locktype==SHARED_LOCK );
2006318507b7Smistachkin     res = osLockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
2007e54ca3feSdrh     if( res ){
2008e54ca3feSdrh       newLocktype = RESERVED_LOCK;
20099db299fbSshane     }else{
2010d1ef9b6dSmistachkin       lastErrno = osGetLastError();
2011e54ca3feSdrh     }
2012e54ca3feSdrh   }
2013e54ca3feSdrh 
2014e54ca3feSdrh   /* Acquire a PENDING lock
2015e54ca3feSdrh   */
2016b3e04346Sdrh   if( locktype==EXCLUSIVE_LOCK && res ){
2017e54ca3feSdrh     newLocktype = PENDING_LOCK;
2018e54ca3feSdrh     gotPendingLock = 0;
201951c6d963Sdrh   }
202051c6d963Sdrh 
202151c6d963Sdrh   /* Acquire an EXCLUSIVE lock
202251c6d963Sdrh   */
2023e54ca3feSdrh   if( locktype==EXCLUSIVE_LOCK && res ){
2024054889ecSdrh     assert( pFile->locktype>=SHARED_LOCK );
2025054889ecSdrh     res = unlockReadLock(pFile);
2026308c2a5cSdrh     OSTRACE(("unreadlock = %d\n", res));
2027318507b7Smistachkin     res = osLockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
2028e54ca3feSdrh     if( res ){
2029e54ca3feSdrh       newLocktype = EXCLUSIVE_LOCK;
2030e54ca3feSdrh     }else{
2031d1ef9b6dSmistachkin       lastErrno = osGetLastError();
2032d1ef9b6dSmistachkin       OSTRACE(("error-code = %d\n", lastErrno));
20338fea1285Sdrh       getReadLock(pFile);
2034e54ca3feSdrh     }
2035e54ca3feSdrh   }
2036e54ca3feSdrh 
2037e54ca3feSdrh   /* If we are holding a PENDING lock that ought to be released, then
2038e54ca3feSdrh   ** release it now.
2039e54ca3feSdrh   */
2040b3e04346Sdrh   if( gotPendingLock && locktype==SHARED_LOCK ){
2041318507b7Smistachkin     osUnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
2042bbd42a6dSdrh   }
204351c6d963Sdrh 
204451c6d963Sdrh   /* Update the state of the lock has held in the file descriptor then
204551c6d963Sdrh   ** return the appropriate result code.
204651c6d963Sdrh   */
2047bbd42a6dSdrh   if( res ){
2048bbd42a6dSdrh     rc = SQLITE_OK;
2049bbd42a6dSdrh   }else{
2050308c2a5cSdrh     OSTRACE(("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
2051308c2a5cSdrh            locktype, newLocktype));
2052d1ef9b6dSmistachkin     pFile->lastErrno = lastErrno;
2053bbd42a6dSdrh     rc = SQLITE_BUSY;
2054bbd42a6dSdrh   }
20551bd10f8aSdrh   pFile->locktype = (u8)newLocktype;
2056bbd42a6dSdrh   return rc;
2057bbd42a6dSdrh }
2058bbd42a6dSdrh 
2059bbd42a6dSdrh /*
206051c6d963Sdrh ** This routine checks if there is a RESERVED lock held on the specified
206151c6d963Sdrh ** file by this or any other process. If such a lock is held, return
206251c6d963Sdrh ** non-zero, otherwise zero.
206351c6d963Sdrh */
2064861f7456Sdanielk1977 static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
206551c6d963Sdrh   int rc;
2066054889ecSdrh   winFile *pFile = (winFile*)id;
206750daafc7Sshane 
2068e2ad9317Sshaneh   SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
2069e2ad9317Sshaneh 
207050daafc7Sshane   assert( id!=0 );
2071054889ecSdrh   if( pFile->locktype>=RESERVED_LOCK ){
207251c6d963Sdrh     rc = 1;
2073308c2a5cSdrh     OSTRACE(("TEST WR-LOCK %d %d (local)\n", pFile->h, rc));
207451c6d963Sdrh   }else{
2075318507b7Smistachkin     rc = osLockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
207651c6d963Sdrh     if( rc ){
2077318507b7Smistachkin       osUnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
207851c6d963Sdrh     }
20792ac3ee97Sdrh     rc = !rc;
2080308c2a5cSdrh     OSTRACE(("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc));
208151c6d963Sdrh   }
2082861f7456Sdanielk1977   *pResOut = rc;
2083861f7456Sdanielk1977   return SQLITE_OK;
208451c6d963Sdrh }
208551c6d963Sdrh 
208651c6d963Sdrh /*
2087a6abd041Sdrh ** Lower the locking level on file descriptor id to locktype.  locktype
2088a6abd041Sdrh ** must be either NO_LOCK or SHARED_LOCK.
2089a6abd041Sdrh **
2090a6abd041Sdrh ** If the locking level of the file descriptor is already at or below
2091a6abd041Sdrh ** the requested locking level, this routine is a no-op.
2092a6abd041Sdrh **
20939c105bb9Sdrh ** It is not possible for this routine to fail if the second argument
20949c105bb9Sdrh ** is NO_LOCK.  If the second argument is SHARED_LOCK then this routine
20959c105bb9Sdrh ** might return SQLITE_IOERR;
2096bbd42a6dSdrh */
2097153c62c4Sdrh static int winUnlock(sqlite3_file *id, int locktype){
20989c105bb9Sdrh   int type;
2099054889ecSdrh   winFile *pFile = (winFile*)id;
2100153c62c4Sdrh   int rc = SQLITE_OK;
2101054889ecSdrh   assert( pFile!=0 );
2102a6abd041Sdrh   assert( locktype<=SHARED_LOCK );
2103308c2a5cSdrh   OSTRACE(("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
2104308c2a5cSdrh           pFile->locktype, pFile->sharedLockByte));
2105054889ecSdrh   type = pFile->locktype;
2106e54ca3feSdrh   if( type>=EXCLUSIVE_LOCK ){
2107318507b7Smistachkin     osUnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
2108054889ecSdrh     if( locktype==SHARED_LOCK && !getReadLock(pFile) ){
21099c105bb9Sdrh       /* This should never happen.  We should always be able to
21109c105bb9Sdrh       ** reacquire the read lock */
2111318507b7Smistachkin       rc = winLogError(SQLITE_IOERR_UNLOCK, osGetLastError(),
21122aef997cSmistachkin                "winUnlock", pFile->zPath);
21139c105bb9Sdrh     }
2114bbd42a6dSdrh   }
2115e54ca3feSdrh   if( type>=RESERVED_LOCK ){
2116318507b7Smistachkin     osUnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
211751c6d963Sdrh   }
21189c105bb9Sdrh   if( locktype==NO_LOCK && type>=SHARED_LOCK ){
2119054889ecSdrh     unlockReadLock(pFile);
212051c6d963Sdrh   }
2121b3e04346Sdrh   if( type>=PENDING_LOCK ){
2122318507b7Smistachkin     osUnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
2123b3e04346Sdrh   }
21241bd10f8aSdrh   pFile->locktype = (u8)locktype;
21259c105bb9Sdrh   return rc;
2126bbd42a6dSdrh }
2127bbd42a6dSdrh 
2128bbd42a6dSdrh /*
21299e33c2c1Sdrh ** Control and query of the open file handle.
21300ccebe7eSdrh */
21319e33c2c1Sdrh static int winFileControl(sqlite3_file *id, int op, void *pArg){
2132f0b190d9Sdrh   winFile *pFile = (winFile*)id;
21339e33c2c1Sdrh   switch( op ){
21349e33c2c1Sdrh     case SQLITE_FCNTL_LOCKSTATE: {
2135f0b190d9Sdrh       *(int*)pArg = pFile->locktype;
21369e33c2c1Sdrh       return SQLITE_OK;
21379cbe6352Sdrh     }
21389db299fbSshane     case SQLITE_LAST_ERRNO: {
2139f0b190d9Sdrh       *(int*)pArg = (int)pFile->lastErrno;
21409db299fbSshane       return SQLITE_OK;
21419db299fbSshane     }
2142502019c8Sdan     case SQLITE_FCNTL_CHUNK_SIZE: {
2143f0b190d9Sdrh       pFile->szChunk = *(int *)pArg;
2144502019c8Sdan       return SQLITE_OK;
2145502019c8Sdan     }
2146f5d6e478Sdrh     case SQLITE_FCNTL_SIZE_HINT: {
2147d589a544Smistachkin       if( pFile->szChunk>0 ){
21484458bc8eSmistachkin         sqlite3_int64 oldSz;
21494458bc8eSmistachkin         int rc = winFileSize(id, &oldSz);
21504458bc8eSmistachkin         if( rc==SQLITE_OK ){
21514458bc8eSmistachkin           sqlite3_int64 newSz = *(sqlite3_int64*)pArg;
21524458bc8eSmistachkin           if( newSz>oldSz ){
2153e2ad9317Sshaneh             SimulateIOErrorBenign(1);
21544458bc8eSmistachkin             rc = winTruncate(id, newSz);
2155e2ad9317Sshaneh             SimulateIOErrorBenign(0);
21564458bc8eSmistachkin           }
21574458bc8eSmistachkin         }
21584458bc8eSmistachkin         return rc;
2159f5d6e478Sdrh       }
2160d589a544Smistachkin       return SQLITE_OK;
2161d589a544Smistachkin     }
2162f0b190d9Sdrh     case SQLITE_FCNTL_PERSIST_WAL: {
2163f0b190d9Sdrh       int bPersist = *(int*)pArg;
2164f0b190d9Sdrh       if( bPersist<0 ){
2165253cea5cSdrh         *(int*)pArg = pFile->bPersistWal;
2166f0b190d9Sdrh       }else{
2167f0b190d9Sdrh         pFile->bPersistWal = bPersist!=0;
2168f0b190d9Sdrh       }
2169f0b190d9Sdrh       return SQLITE_OK;
2170f0b190d9Sdrh     }
21710b52b7d0Sdrh     case SQLITE_FCNTL_SYNC_OMITTED: {
21720b52b7d0Sdrh       return SQLITE_OK;
21739e33c2c1Sdrh     }
2174d0cdf012Sdrh     case SQLITE_FCNTL_WIN32_AV_RETRY: {
2175d0cdf012Sdrh       int *a = (int*)pArg;
2176d0cdf012Sdrh       if( a[0]>0 ){
2177d0cdf012Sdrh         win32IoerrRetry = a[0];
2178d0cdf012Sdrh       }else{
2179d0cdf012Sdrh         a[0] = win32IoerrRetry;
2180d0cdf012Sdrh       }
2181d0cdf012Sdrh       if( a[1]>0 ){
2182d0cdf012Sdrh         win32IoerrRetryDelay = a[1];
2183d0cdf012Sdrh       }else{
2184d0cdf012Sdrh         a[1] = win32IoerrRetryDelay;
2185d0cdf012Sdrh       }
2186d0cdf012Sdrh       return SQLITE_OK;
2187d0cdf012Sdrh     }
21880b52b7d0Sdrh   }
21890b52b7d0Sdrh   return SQLITE_NOTFOUND;
219018839217Sdrh }
219118839217Sdrh 
219218839217Sdrh /*
2193a3d4c887Sdanielk1977 ** Return the sector size in bytes of the underlying block device for
2194a3d4c887Sdanielk1977 ** the specified file. This is almost always 512 bytes, but may be
2195a3d4c887Sdanielk1977 ** larger for some devices.
2196a3d4c887Sdanielk1977 **
2197a3d4c887Sdanielk1977 ** SQLite code assumes this function cannot fail. It also assumes that
2198a3d4c887Sdanielk1977 ** if two files are created in the same file-system directory (i.e.
219985b623f2Sdrh ** a database and its journal file) that the sector size will be the
2200a3d4c887Sdanielk1977 ** same for both.
2201a3d4c887Sdanielk1977 */
2202153c62c4Sdrh static int winSectorSize(sqlite3_file *id){
220350daafc7Sshane   assert( id!=0 );
220450daafc7Sshane   return (int)(((winFile*)id)->sectorSize);
2205a3d4c887Sdanielk1977 }
2206a3d4c887Sdanielk1977 
2207a3d4c887Sdanielk1977 /*
2208153c62c4Sdrh ** Return a vector of device characteristics.
22099c06c953Sdrh */
2210153c62c4Sdrh static int winDeviceCharacteristics(sqlite3_file *id){
221118e526c1Sshane   UNUSED_PARAMETER(id);
22128ce49d6aSdan   return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
2213153c62c4Sdrh }
2214153c62c4Sdrh 
221583235214Sdrh #ifndef SQLITE_OMIT_WAL
221683235214Sdrh 
221783235214Sdrh /*
2218420398ceSshaneh ** Windows will only let you create file view mappings
2219420398ceSshaneh ** on allocation size granularity boundaries.
2220420398ceSshaneh ** During sqlite3_os_init() we do a GetSystemInfo()
2221420398ceSshaneh ** to get the granularity size.
2222420398ceSshaneh */
2223420398ceSshaneh SYSTEM_INFO winSysInfo;
2224420398ceSshaneh 
2225420398ceSshaneh /*
222683235214Sdrh ** Helper functions to obtain and relinquish the global mutex. The
222783235214Sdrh ** global mutex is used to protect the winLockInfo objects used by
222883235214Sdrh ** this file, all of which may be shared by multiple threads.
222983235214Sdrh **
223083235214Sdrh ** Function winShmMutexHeld() is used to assert() that the global mutex
223183235214Sdrh ** is held when required. This function is only used as part of assert()
223283235214Sdrh ** statements. e.g.
223383235214Sdrh **
223483235214Sdrh **   winShmEnterMutex()
223583235214Sdrh **     assert( winShmMutexHeld() );
2236d5a72400Sshaneh **   winShmLeaveMutex()
223783235214Sdrh */
223883235214Sdrh static void winShmEnterMutex(void){
223983235214Sdrh   sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
224083235214Sdrh }
224183235214Sdrh static void winShmLeaveMutex(void){
224283235214Sdrh   sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
224383235214Sdrh }
224483235214Sdrh #ifdef SQLITE_DEBUG
224583235214Sdrh static int winShmMutexHeld(void) {
224683235214Sdrh   return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
224783235214Sdrh }
224883235214Sdrh #endif
224983235214Sdrh 
225083235214Sdrh /*
225183235214Sdrh ** Object used to represent a single file opened and mmapped to provide
225283235214Sdrh ** shared memory.  When multiple threads all reference the same
225383235214Sdrh ** log-summary, each thread has its own winFile object, but they all
225483235214Sdrh ** point to a single instance of this object.  In other words, each
225583235214Sdrh ** log-summary is opened only once per process.
225683235214Sdrh **
225783235214Sdrh ** winShmMutexHeld() must be true when creating or destroying
225883235214Sdrh ** this object or while reading or writing the following fields:
225983235214Sdrh **
226083235214Sdrh **      nRef
226183235214Sdrh **      pNext
226283235214Sdrh **
226383235214Sdrh ** The following fields are read-only after the object is created:
226483235214Sdrh **
226583235214Sdrh **      fid
226683235214Sdrh **      zFilename
226783235214Sdrh **
226883235214Sdrh ** Either winShmNode.mutex must be held or winShmNode.nRef==0 and
226983235214Sdrh ** winShmMutexHeld() is true when reading or writing any other field
227083235214Sdrh ** in this structure.
227183235214Sdrh **
227283235214Sdrh */
227383235214Sdrh struct winShmNode {
227483235214Sdrh   sqlite3_mutex *mutex;      /* Mutex to access this object */
227583235214Sdrh   char *zFilename;           /* Name of the file */
227683235214Sdrh   winFile hFile;             /* File handle from winOpen */
22779785fc95Sdan 
22789785fc95Sdan   int szRegion;              /* Size of shared-memory regions */
22799785fc95Sdan   int nRegion;               /* Size of array apRegion */
22809785fc95Sdan   struct ShmRegion {
228183235214Sdrh     HANDLE hMap;             /* File handle from CreateFileMapping */
22829785fc95Sdan     void *pMap;
22839785fc95Sdan   } *aRegion;
228483235214Sdrh   DWORD lastErrno;           /* The Windows errno from the last I/O error */
22859785fc95Sdan 
228683235214Sdrh   int nRef;                  /* Number of winShm objects pointing to this */
228783235214Sdrh   winShm *pFirst;            /* All winShm objects pointing to this */
228883235214Sdrh   winShmNode *pNext;         /* Next in list of all winShmNode objects */
228983235214Sdrh #ifdef SQLITE_DEBUG
229083235214Sdrh   u8 nextShmId;              /* Next available winShm.id value */
229183235214Sdrh #endif
229283235214Sdrh };
229383235214Sdrh 
229483235214Sdrh /*
229583235214Sdrh ** A global array of all winShmNode objects.
229683235214Sdrh **
229783235214Sdrh ** The winShmMutexHeld() must be true while reading or writing this list.
229883235214Sdrh */
229983235214Sdrh static winShmNode *winShmNodeList = 0;
230083235214Sdrh 
230183235214Sdrh /*
230283235214Sdrh ** Structure used internally by this VFS to record the state of an
230383235214Sdrh ** open shared memory connection.
230483235214Sdrh **
23051f3e27b2Sshaneh ** The following fields are initialized when this object is created and
23061f3e27b2Sshaneh ** are read-only thereafter:
230783235214Sdrh **
23081f3e27b2Sshaneh **    winShm.pShmNode
23091f3e27b2Sshaneh **    winShm.id
23101f3e27b2Sshaneh **
23111f3e27b2Sshaneh ** All other fields are read/write.  The winShm.pShmNode->mutex must be held
23121f3e27b2Sshaneh ** while accessing any read/write fields.
231383235214Sdrh */
231483235214Sdrh struct winShm {
231583235214Sdrh   winShmNode *pShmNode;      /* The underlying winShmNode object */
231683235214Sdrh   winShm *pNext;             /* Next winShm with the same winShmNode */
231783235214Sdrh   u8 hasMutex;               /* True if holding the winShmNode mutex */
23181f3e27b2Sshaneh   u16 sharedMask;            /* Mask of shared locks held */
23191f3e27b2Sshaneh   u16 exclMask;              /* Mask of exclusive locks held */
232083235214Sdrh #ifdef SQLITE_DEBUG
232183235214Sdrh   u8 id;                     /* Id of this connection with its winShmNode */
232283235214Sdrh #endif
232383235214Sdrh };
232483235214Sdrh 
232583235214Sdrh /*
232683235214Sdrh ** Constants used for locking
232783235214Sdrh */
2328bd9676c1Sdrh #define WIN_SHM_BASE   ((22+SQLITE_SHM_NLOCK)*4)        /* first lock byte */
232920e1f08eSdrh #define WIN_SHM_DMS    (WIN_SHM_BASE+SQLITE_SHM_NLOCK)  /* deadman switch */
233083235214Sdrh 
233183235214Sdrh /*
233220e1f08eSdrh ** Apply advisory locks for all n bytes beginning at ofst.
233383235214Sdrh */
233483235214Sdrh #define _SHM_UNLCK  1
233583235214Sdrh #define _SHM_RDLCK  2
233683235214Sdrh #define _SHM_WRLCK  3
233783235214Sdrh static int winShmSystemLock(
233883235214Sdrh   winShmNode *pFile,    /* Apply locks to this open shared-memory segment */
233983235214Sdrh   int lockType,         /* _SHM_UNLCK, _SHM_RDLCK, or _SHM_WRLCK */
234020e1f08eSdrh   int ofst,             /* Offset to first byte to be locked/unlocked */
234120e1f08eSdrh   int nByte             /* Number of bytes to lock or unlock */
234283235214Sdrh ){
234383235214Sdrh   OVERLAPPED ovlp;
234483235214Sdrh   DWORD dwFlags;
234583235214Sdrh   int rc = 0;           /* Result code form Lock/UnlockFileEx() */
234683235214Sdrh 
234783235214Sdrh   /* Access to the winShmNode object is serialized by the caller */
234883235214Sdrh   assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
234983235214Sdrh 
235083235214Sdrh   /* Initialize the locking parameters */
235183235214Sdrh   dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
235283235214Sdrh   if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
235383235214Sdrh 
235483235214Sdrh   memset(&ovlp, 0, sizeof(OVERLAPPED));
235520e1f08eSdrh   ovlp.Offset = ofst;
235683235214Sdrh 
235783235214Sdrh   /* Release/Acquire the system-level lock */
235883235214Sdrh   if( lockType==_SHM_UNLCK ){
2359318507b7Smistachkin     rc = osUnlockFileEx(pFile->hFile.h, 0, nByte, 0, &ovlp);
236083235214Sdrh   }else{
2361318507b7Smistachkin     rc = osLockFileEx(pFile->hFile.h, dwFlags, 0, nByte, 0, &ovlp);
236283235214Sdrh   }
2363d5a72400Sshaneh 
2364d5a72400Sshaneh   if( rc!= 0 ){
2365d5a72400Sshaneh     rc = SQLITE_OK;
2366d5a72400Sshaneh   }else{
2367318507b7Smistachkin     pFile->lastErrno =  osGetLastError();
2368d5a72400Sshaneh     rc = SQLITE_BUSY;
2369d5a72400Sshaneh   }
23701f3e27b2Sshaneh 
23711f3e27b2Sshaneh   OSTRACE(("SHM-LOCK %d %s %s 0x%08lx\n",
237283235214Sdrh            pFile->hFile.h,
23731f3e27b2Sshaneh            rc==SQLITE_OK ? "ok" : "failed",
237483235214Sdrh            lockType==_SHM_UNLCK ? "UnlockFileEx" : "LockFileEx",
2375d5a72400Sshaneh            pFile->lastErrno));
237683235214Sdrh 
237783235214Sdrh   return rc;
237883235214Sdrh }
237983235214Sdrh 
238005cb5b24Sdrh /* Forward references to VFS methods */
238105cb5b24Sdrh static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*);
238205cb5b24Sdrh static int winDelete(sqlite3_vfs *,const char*,int);
238305cb5b24Sdrh 
238483235214Sdrh /*
238583235214Sdrh ** Purge the winShmNodeList list of all entries with winShmNode.nRef==0.
238683235214Sdrh **
238783235214Sdrh ** This is not a VFS shared-memory method; it is a utility function called
238883235214Sdrh ** by VFS shared-memory methods.
238983235214Sdrh */
239005cb5b24Sdrh static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
239183235214Sdrh   winShmNode **pp;
239283235214Sdrh   winShmNode *p;
2393420398ceSshaneh   BOOL bRc;
239483235214Sdrh   assert( winShmMutexHeld() );
239583235214Sdrh   pp = &winShmNodeList;
239683235214Sdrh   while( (p = *pp)!=0 ){
239783235214Sdrh     if( p->nRef==0 ){
23989785fc95Sdan       int i;
239983235214Sdrh       if( p->mutex ) sqlite3_mutex_free(p->mutex);
24009785fc95Sdan       for(i=0; i<p->nRegion; i++){
2401318507b7Smistachkin         bRc = osUnmapViewOfFile(p->aRegion[i].pMap);
2402420398ceSshaneh         OSTRACE(("SHM-PURGE pid-%d unmap region=%d %s\n",
2403318507b7Smistachkin                  (int)osGetCurrentProcessId(), i,
2404420398ceSshaneh                  bRc ? "ok" : "failed"));
2405318507b7Smistachkin         bRc = osCloseHandle(p->aRegion[i].hMap);
2406420398ceSshaneh         OSTRACE(("SHM-PURGE pid-%d close region=%d %s\n",
2407318507b7Smistachkin                  (int)osGetCurrentProcessId(), i,
2408420398ceSshaneh                  bRc ? "ok" : "failed"));
240983235214Sdrh       }
241083235214Sdrh       if( p->hFile.h != INVALID_HANDLE_VALUE ){
2411e2ad9317Sshaneh         SimulateIOErrorBenign(1);
241283235214Sdrh         winClose((sqlite3_file *)&p->hFile);
2413e2ad9317Sshaneh         SimulateIOErrorBenign(0);
241483235214Sdrh       }
2415e2ad9317Sshaneh       if( deleteFlag ){
2416e2ad9317Sshaneh         SimulateIOErrorBenign(1);
2417e2ad9317Sshaneh         winDelete(pVfs, p->zFilename, 0);
2418e2ad9317Sshaneh         SimulateIOErrorBenign(0);
2419e2ad9317Sshaneh       }
242083235214Sdrh       *pp = p->pNext;
24219785fc95Sdan       sqlite3_free(p->aRegion);
242283235214Sdrh       sqlite3_free(p);
242383235214Sdrh     }else{
242483235214Sdrh       pp = &p->pNext;
242583235214Sdrh     }
242683235214Sdrh   }
242783235214Sdrh }
242883235214Sdrh 
242983235214Sdrh /*
2430da9fe0c3Sdan ** Open the shared-memory area associated with database file pDbFd.
243183235214Sdrh **
243283235214Sdrh ** When opening a new shared-memory file, if no other instances of that
243383235214Sdrh ** file are currently open, in this process or in other processes, then
243483235214Sdrh ** the file must be truncated to zero length or have its header cleared.
243583235214Sdrh */
2436da9fe0c3Sdan static int winOpenSharedMemory(winFile *pDbFd){
243783235214Sdrh   struct winShm *p;                  /* The connection to be opened */
243883235214Sdrh   struct winShmNode *pShmNode = 0;   /* The underlying mmapped file */
243983235214Sdrh   int rc;                            /* Result code */
244083235214Sdrh   struct winShmNode *pNew;           /* Newly allocated winShmNode */
244183235214Sdrh   int nName;                         /* Size of zName in bytes */
244283235214Sdrh 
244383235214Sdrh   assert( pDbFd->pShm==0 );    /* Not previously opened */
244483235214Sdrh 
244583235214Sdrh   /* Allocate space for the new sqlite3_shm object.  Also speculatively
244683235214Sdrh   ** allocate space for a new winShmNode and filename.
244783235214Sdrh   */
244883235214Sdrh   p = sqlite3_malloc( sizeof(*p) );
24495f075388Smistachkin   if( p==0 ) return SQLITE_IOERR_NOMEM;
245083235214Sdrh   memset(p, 0, sizeof(*p));
245183235214Sdrh   nName = sqlite3Strlen30(pDbFd->zPath);
245283235214Sdrh   pNew = sqlite3_malloc( sizeof(*pShmNode) + nName + 15 );
245383235214Sdrh   if( pNew==0 ){
245483235214Sdrh     sqlite3_free(p);
24555f075388Smistachkin     return SQLITE_IOERR_NOMEM;
245683235214Sdrh   }
245783235214Sdrh   memset(pNew, 0, sizeof(*pNew));
245883235214Sdrh   pNew->zFilename = (char*)&pNew[1];
2459d36f660dSdrh   sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
246081cc5163Sdrh   sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename);
246183235214Sdrh 
246283235214Sdrh   /* Look to see if there is an existing winShmNode that can be used.
246383235214Sdrh   ** If no matching winShmNode currently exists, create a new one.
246483235214Sdrh   */
246583235214Sdrh   winShmEnterMutex();
246683235214Sdrh   for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){
246783235214Sdrh     /* TBD need to come up with better match here.  Perhaps
246883235214Sdrh     ** use FILE_ID_BOTH_DIR_INFO Structure.
246983235214Sdrh     */
247083235214Sdrh     if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break;
247183235214Sdrh   }
247283235214Sdrh   if( pShmNode ){
247383235214Sdrh     sqlite3_free(pNew);
247483235214Sdrh   }else{
247583235214Sdrh     pShmNode = pNew;
247683235214Sdrh     pNew = 0;
247783235214Sdrh     ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE;
247883235214Sdrh     pShmNode->pNext = winShmNodeList;
247983235214Sdrh     winShmNodeList = pShmNode;
248083235214Sdrh 
248183235214Sdrh     pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
248283235214Sdrh     if( pShmNode->mutex==0 ){
24835f075388Smistachkin       rc = SQLITE_IOERR_NOMEM;
248483235214Sdrh       goto shm_open_err;
248583235214Sdrh     }
2486420398ceSshaneh 
248783235214Sdrh     rc = winOpen(pDbFd->pVfs,
248883235214Sdrh                  pShmNode->zFilename,             /* Name of the file (UTF-8) */
248983235214Sdrh                  (sqlite3_file*)&pShmNode->hFile,  /* File handle here */
2490f7b5f855Sshaneh                  SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, /* Mode flags */
249183235214Sdrh                  0);
249283235214Sdrh     if( SQLITE_OK!=rc ){
249383235214Sdrh       rc = SQLITE_CANTOPEN_BKPT;
249483235214Sdrh       goto shm_open_err;
249583235214Sdrh     }
249683235214Sdrh 
249783235214Sdrh     /* Check to see if another process is holding the dead-man switch.
249883235214Sdrh     ** If not, truncate the file to zero length.
249983235214Sdrh     */
250020e1f08eSdrh     if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
250183235214Sdrh       rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
2502fd28639fSshaneh       if( rc!=SQLITE_OK ){
2503318507b7Smistachkin         rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
25042aef997cSmistachkin                  "winOpenShm", pDbFd->zPath);
2505fd28639fSshaneh       }
250683235214Sdrh     }
250783235214Sdrh     if( rc==SQLITE_OK ){
250820e1f08eSdrh       winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
250920e1f08eSdrh       rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1);
251083235214Sdrh     }
251183235214Sdrh     if( rc ) goto shm_open_err;
251283235214Sdrh   }
251383235214Sdrh 
251483235214Sdrh   /* Make the new connection a child of the winShmNode */
251583235214Sdrh   p->pShmNode = pShmNode;
251683235214Sdrh #ifdef SQLITE_DEBUG
251783235214Sdrh   p->id = pShmNode->nextShmId++;
251883235214Sdrh #endif
251983235214Sdrh   pShmNode->nRef++;
252083235214Sdrh   pDbFd->pShm = p;
252183235214Sdrh   winShmLeaveMutex();
2522d5a72400Sshaneh 
2523d5a72400Sshaneh   /* The reference count on pShmNode has already been incremented under
2524d5a72400Sshaneh   ** the cover of the winShmEnterMutex() mutex and the pointer from the
2525d5a72400Sshaneh   ** new (struct winShm) object to the pShmNode has been set. All that is
2526d5a72400Sshaneh   ** left to do is to link the new object into the linked list starting
2527d5a72400Sshaneh   ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex
2528d5a72400Sshaneh   ** mutex.
2529d5a72400Sshaneh   */
2530d5a72400Sshaneh   sqlite3_mutex_enter(pShmNode->mutex);
2531d5a72400Sshaneh   p->pNext = pShmNode->pFirst;
2532d5a72400Sshaneh   pShmNode->pFirst = p;
2533d5a72400Sshaneh   sqlite3_mutex_leave(pShmNode->mutex);
253483235214Sdrh   return SQLITE_OK;
253583235214Sdrh 
253683235214Sdrh   /* Jump here on any error */
253783235214Sdrh shm_open_err:
253820e1f08eSdrh   winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
253905cb5b24Sdrh   winShmPurge(pDbFd->pVfs, 0);      /* This call frees pShmNode if required */
254083235214Sdrh   sqlite3_free(p);
254183235214Sdrh   sqlite3_free(pNew);
254283235214Sdrh   winShmLeaveMutex();
254383235214Sdrh   return rc;
254483235214Sdrh }
254583235214Sdrh 
254683235214Sdrh /*
254783235214Sdrh ** Close a connection to shared-memory.  Delete the underlying
254883235214Sdrh ** storage if deleteFlag is true.
254983235214Sdrh */
2550e11fedc5Sdrh static int winShmUnmap(
255183235214Sdrh   sqlite3_file *fd,          /* Database holding shared memory */
255283235214Sdrh   int deleteFlag             /* Delete after closing if true */
255383235214Sdrh ){
255483235214Sdrh   winFile *pDbFd;       /* Database holding shared-memory */
255583235214Sdrh   winShm *p;            /* The connection to be closed */
255683235214Sdrh   winShmNode *pShmNode; /* The underlying shared-memory file */
255783235214Sdrh   winShm **pp;          /* For looping over sibling connections */
255883235214Sdrh 
255983235214Sdrh   pDbFd = (winFile*)fd;
256083235214Sdrh   p = pDbFd->pShm;
25611f3e27b2Sshaneh   if( p==0 ) return SQLITE_OK;
256283235214Sdrh   pShmNode = p->pShmNode;
256383235214Sdrh 
256483235214Sdrh   /* Remove connection p from the set of connections associated
256583235214Sdrh   ** with pShmNode */
256683235214Sdrh   sqlite3_mutex_enter(pShmNode->mutex);
256783235214Sdrh   for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
256883235214Sdrh   *pp = p->pNext;
256983235214Sdrh 
257083235214Sdrh   /* Free the connection p */
257183235214Sdrh   sqlite3_free(p);
257283235214Sdrh   pDbFd->pShm = 0;
257383235214Sdrh   sqlite3_mutex_leave(pShmNode->mutex);
257483235214Sdrh 
257583235214Sdrh   /* If pShmNode->nRef has reached 0, then close the underlying
257683235214Sdrh   ** shared-memory file, too */
257783235214Sdrh   winShmEnterMutex();
257883235214Sdrh   assert( pShmNode->nRef>0 );
257983235214Sdrh   pShmNode->nRef--;
258083235214Sdrh   if( pShmNode->nRef==0 ){
258105cb5b24Sdrh     winShmPurge(pDbFd->pVfs, deleteFlag);
258283235214Sdrh   }
258383235214Sdrh   winShmLeaveMutex();
258483235214Sdrh 
258583235214Sdrh   return SQLITE_OK;
258683235214Sdrh }
258783235214Sdrh 
258883235214Sdrh /*
25891f3e27b2Sshaneh ** Change the lock state for a shared-memory segment.
25901f3e27b2Sshaneh */
25911f3e27b2Sshaneh static int winShmLock(
25921f3e27b2Sshaneh   sqlite3_file *fd,          /* Database file holding the shared memory */
25931f3e27b2Sshaneh   int ofst,                  /* First lock to acquire or release */
25941f3e27b2Sshaneh   int n,                     /* Number of locks to acquire or release */
25951f3e27b2Sshaneh   int flags                  /* What to do with the lock */
25961f3e27b2Sshaneh ){
25971f3e27b2Sshaneh   winFile *pDbFd = (winFile*)fd;        /* Connection holding shared memory */
25981f3e27b2Sshaneh   winShm *p = pDbFd->pShm;              /* The shared memory being locked */
25991f3e27b2Sshaneh   winShm *pX;                           /* For looping over all siblings */
26001f3e27b2Sshaneh   winShmNode *pShmNode = p->pShmNode;
26011f3e27b2Sshaneh   int rc = SQLITE_OK;                   /* Result code */
26021f3e27b2Sshaneh   u16 mask;                             /* Mask of locks to take or release */
26031f3e27b2Sshaneh 
26041f3e27b2Sshaneh   assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
26051f3e27b2Sshaneh   assert( n>=1 );
26061f3e27b2Sshaneh   assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
26071f3e27b2Sshaneh        || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
26081f3e27b2Sshaneh        || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
26091f3e27b2Sshaneh        || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
26101f3e27b2Sshaneh   assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
26111f3e27b2Sshaneh 
26121f3e27b2Sshaneh   mask = (u16)((1U<<(ofst+n)) - (1U<<ofst));
26131f3e27b2Sshaneh   assert( n>1 || mask==(1<<ofst) );
26141f3e27b2Sshaneh   sqlite3_mutex_enter(pShmNode->mutex);
26151f3e27b2Sshaneh   if( flags & SQLITE_SHM_UNLOCK ){
26161f3e27b2Sshaneh     u16 allMask = 0; /* Mask of locks held by siblings */
26171f3e27b2Sshaneh 
26181f3e27b2Sshaneh     /* See if any siblings hold this same lock */
26191f3e27b2Sshaneh     for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
26201f3e27b2Sshaneh       if( pX==p ) continue;
26211f3e27b2Sshaneh       assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
26221f3e27b2Sshaneh       allMask |= pX->sharedMask;
26231f3e27b2Sshaneh     }
26241f3e27b2Sshaneh 
26251f3e27b2Sshaneh     /* Unlock the system-level locks */
26261f3e27b2Sshaneh     if( (mask & allMask)==0 ){
26271f3e27b2Sshaneh       rc = winShmSystemLock(pShmNode, _SHM_UNLCK, ofst+WIN_SHM_BASE, n);
26281f3e27b2Sshaneh     }else{
26291f3e27b2Sshaneh       rc = SQLITE_OK;
26301f3e27b2Sshaneh     }
26311f3e27b2Sshaneh 
26321f3e27b2Sshaneh     /* Undo the local locks */
26331f3e27b2Sshaneh     if( rc==SQLITE_OK ){
26341f3e27b2Sshaneh       p->exclMask &= ~mask;
26351f3e27b2Sshaneh       p->sharedMask &= ~mask;
26361f3e27b2Sshaneh     }
26371f3e27b2Sshaneh   }else if( flags & SQLITE_SHM_SHARED ){
26381f3e27b2Sshaneh     u16 allShared = 0;  /* Union of locks held by connections other than "p" */
26391f3e27b2Sshaneh 
26401f3e27b2Sshaneh     /* Find out which shared locks are already held by sibling connections.
26411f3e27b2Sshaneh     ** If any sibling already holds an exclusive lock, go ahead and return
26421f3e27b2Sshaneh     ** SQLITE_BUSY.
26431f3e27b2Sshaneh     */
26441f3e27b2Sshaneh     for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
26451f3e27b2Sshaneh       if( (pX->exclMask & mask)!=0 ){
26461f3e27b2Sshaneh         rc = SQLITE_BUSY;
26471f3e27b2Sshaneh         break;
26481f3e27b2Sshaneh       }
26491f3e27b2Sshaneh       allShared |= pX->sharedMask;
26501f3e27b2Sshaneh     }
26511f3e27b2Sshaneh 
26521f3e27b2Sshaneh     /* Get shared locks at the system level, if necessary */
26531f3e27b2Sshaneh     if( rc==SQLITE_OK ){
26541f3e27b2Sshaneh       if( (allShared & mask)==0 ){
26551f3e27b2Sshaneh         rc = winShmSystemLock(pShmNode, _SHM_RDLCK, ofst+WIN_SHM_BASE, n);
26561f3e27b2Sshaneh       }else{
26571f3e27b2Sshaneh         rc = SQLITE_OK;
26581f3e27b2Sshaneh       }
26591f3e27b2Sshaneh     }
26601f3e27b2Sshaneh 
26611f3e27b2Sshaneh     /* Get the local shared locks */
26621f3e27b2Sshaneh     if( rc==SQLITE_OK ){
26631f3e27b2Sshaneh       p->sharedMask |= mask;
26641f3e27b2Sshaneh     }
26651f3e27b2Sshaneh   }else{
26661f3e27b2Sshaneh     /* Make sure no sibling connections hold locks that will block this
26671f3e27b2Sshaneh     ** lock.  If any do, return SQLITE_BUSY right away.
26681f3e27b2Sshaneh     */
26691f3e27b2Sshaneh     for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
26701f3e27b2Sshaneh       if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
26711f3e27b2Sshaneh         rc = SQLITE_BUSY;
26721f3e27b2Sshaneh         break;
26731f3e27b2Sshaneh       }
26741f3e27b2Sshaneh     }
26751f3e27b2Sshaneh 
26761f3e27b2Sshaneh     /* Get the exclusive locks at the system level.  Then if successful
26771f3e27b2Sshaneh     ** also mark the local connection as being locked.
26781f3e27b2Sshaneh     */
26791f3e27b2Sshaneh     if( rc==SQLITE_OK ){
26801f3e27b2Sshaneh       rc = winShmSystemLock(pShmNode, _SHM_WRLCK, ofst+WIN_SHM_BASE, n);
26811f3e27b2Sshaneh       if( rc==SQLITE_OK ){
26821f3e27b2Sshaneh         assert( (p->sharedMask & mask)==0 );
26831f3e27b2Sshaneh         p->exclMask |= mask;
26841f3e27b2Sshaneh       }
26851f3e27b2Sshaneh     }
26861f3e27b2Sshaneh   }
26871f3e27b2Sshaneh   sqlite3_mutex_leave(pShmNode->mutex);
26881f3e27b2Sshaneh   OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x %s\n",
2689318507b7Smistachkin            p->id, (int)osGetCurrentProcessId(), p->sharedMask, p->exclMask,
26901f3e27b2Sshaneh            rc ? "failed" : "ok"));
26911f3e27b2Sshaneh   return rc;
26921f3e27b2Sshaneh }
26931f3e27b2Sshaneh 
26941f3e27b2Sshaneh /*
26951f3e27b2Sshaneh ** Implement a memory barrier or memory fence on shared memory.
26961f3e27b2Sshaneh **
26971f3e27b2Sshaneh ** All loads and stores begun before the barrier must complete before
26981f3e27b2Sshaneh ** any load or store begun after the barrier.
26991f3e27b2Sshaneh */
27001f3e27b2Sshaneh static void winShmBarrier(
27011f3e27b2Sshaneh   sqlite3_file *fd          /* Database holding the shared memory */
27021f3e27b2Sshaneh ){
27031f3e27b2Sshaneh   UNUSED_PARAMETER(fd);
27041f3e27b2Sshaneh   /* MemoryBarrier(); // does not work -- do not know why not */
27051f3e27b2Sshaneh   winShmEnterMutex();
27061f3e27b2Sshaneh   winShmLeaveMutex();
27071f3e27b2Sshaneh }
27081f3e27b2Sshaneh 
27091f3e27b2Sshaneh /*
27109785fc95Sdan ** This function is called to obtain a pointer to region iRegion of the
27119785fc95Sdan ** shared-memory associated with the database file fd. Shared-memory regions
27129785fc95Sdan ** are numbered starting from zero. Each shared-memory region is szRegion
27139785fc95Sdan ** bytes in size.
271483235214Sdrh **
27159785fc95Sdan ** If an error occurs, an error code is returned and *pp is set to NULL.
271683235214Sdrh **
27179785fc95Sdan ** Otherwise, if the isWrite parameter is 0 and the requested shared-memory
27189785fc95Sdan ** region has not been allocated (by any client, including one running in a
27199785fc95Sdan ** separate process), then *pp is set to NULL and SQLITE_OK returned. If
27209785fc95Sdan ** isWrite is non-zero and the requested shared-memory region has not yet
27219785fc95Sdan ** been allocated, it is allocated by this function.
27229785fc95Sdan **
27239785fc95Sdan ** If the shared-memory region has already been allocated or is allocated by
27249785fc95Sdan ** this call as described above, then it is mapped into this processes
27259785fc95Sdan ** address space (if it is not already), *pp is set to point to the mapped
27269785fc95Sdan ** memory and SQLITE_OK returned.
272783235214Sdrh */
27289785fc95Sdan static int winShmMap(
27299785fc95Sdan   sqlite3_file *fd,               /* Handle open on database file */
27309785fc95Sdan   int iRegion,                    /* Region to retrieve */
27319785fc95Sdan   int szRegion,                   /* Size of regions */
27329785fc95Sdan   int isWrite,                    /* True to extend file if necessary */
27339785fc95Sdan   void volatile **pp              /* OUT: Mapped memory */
273483235214Sdrh ){
273583235214Sdrh   winFile *pDbFd = (winFile*)fd;
273683235214Sdrh   winShm *p = pDbFd->pShm;
2737da9fe0c3Sdan   winShmNode *pShmNode;
273883235214Sdrh   int rc = SQLITE_OK;
273983235214Sdrh 
2740da9fe0c3Sdan   if( !p ){
2741da9fe0c3Sdan     rc = winOpenSharedMemory(pDbFd);
2742da9fe0c3Sdan     if( rc!=SQLITE_OK ) return rc;
2743da9fe0c3Sdan     p = pDbFd->pShm;
2744da9fe0c3Sdan   }
2745da9fe0c3Sdan   pShmNode = p->pShmNode;
2746da9fe0c3Sdan 
274783235214Sdrh   sqlite3_mutex_enter(pShmNode->mutex);
27489785fc95Sdan   assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
27499785fc95Sdan 
27509785fc95Sdan   if( pShmNode->nRegion<=iRegion ){
27519785fc95Sdan     struct ShmRegion *apNew;           /* New aRegion[] array */
27529785fc95Sdan     int nByte = (iRegion+1)*szRegion;  /* Minimum required file size */
27539785fc95Sdan     sqlite3_int64 sz;                  /* Current size of wal-index file */
27549785fc95Sdan 
27559785fc95Sdan     pShmNode->szRegion = szRegion;
27569785fc95Sdan 
27579785fc95Sdan     /* The requested region is not mapped into this processes address space.
27589785fc95Sdan     ** Check to see if it has been allocated (i.e. if the wal-index file is
27599785fc95Sdan     ** large enough to contain the requested region).
276083235214Sdrh     */
27619785fc95Sdan     rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz);
27629785fc95Sdan     if( rc!=SQLITE_OK ){
2763318507b7Smistachkin       rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(),
27642aef997cSmistachkin                "winShmMap1", pDbFd->zPath);
27659785fc95Sdan       goto shmpage_out;
276683235214Sdrh     }
27679785fc95Sdan 
27689785fc95Sdan     if( sz<nByte ){
27699785fc95Sdan       /* The requested memory region does not exist. If isWrite is set to
27709785fc95Sdan       ** zero, exit early. *pp will be set to NULL and SQLITE_OK returned.
27719785fc95Sdan       **
27729785fc95Sdan       ** Alternatively, if isWrite is non-zero, use ftruncate() to allocate
27739785fc95Sdan       ** the requested memory region.
27749785fc95Sdan       */
27759785fc95Sdan       if( !isWrite ) goto shmpage_out;
27769785fc95Sdan       rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte);
27779785fc95Sdan       if( rc!=SQLITE_OK ){
2778318507b7Smistachkin         rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(),
27792aef997cSmistachkin                  "winShmMap2", pDbFd->zPath);
27809785fc95Sdan         goto shmpage_out;
27819785fc95Sdan       }
27829785fc95Sdan     }
27839785fc95Sdan 
27849785fc95Sdan     /* Map the requested memory region into this processes address space. */
27859785fc95Sdan     apNew = (struct ShmRegion *)sqlite3_realloc(
27869785fc95Sdan         pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
27879785fc95Sdan     );
27889785fc95Sdan     if( !apNew ){
27899785fc95Sdan       rc = SQLITE_IOERR_NOMEM;
27909785fc95Sdan       goto shmpage_out;
27919785fc95Sdan     }
27929785fc95Sdan     pShmNode->aRegion = apNew;
27939785fc95Sdan 
27949785fc95Sdan     while( pShmNode->nRegion<=iRegion ){
27959785fc95Sdan       HANDLE hMap;                /* file-mapping handle */
27969785fc95Sdan       void *pMap = 0;             /* Mapped memory region */
27979785fc95Sdan 
2798318507b7Smistachkin       hMap = osCreateFileMapping(pShmNode->hFile.h,
27999785fc95Sdan           NULL, PAGE_READWRITE, 0, nByte, NULL
28009785fc95Sdan       );
2801420398ceSshaneh       OSTRACE(("SHM-MAP pid-%d create region=%d nbyte=%d %s\n",
2802318507b7Smistachkin                (int)osGetCurrentProcessId(), pShmNode->nRegion, nByte,
2803420398ceSshaneh                hMap ? "ok" : "failed"));
28049785fc95Sdan       if( hMap ){
2805420398ceSshaneh         int iOffset = pShmNode->nRegion*szRegion;
2806420398ceSshaneh         int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
2807318507b7Smistachkin         pMap = osMapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
2808420398ceSshaneh             0, iOffset - iOffsetShift, szRegion + iOffsetShift
28099785fc95Sdan         );
2810420398ceSshaneh         OSTRACE(("SHM-MAP pid-%d map region=%d offset=%d size=%d %s\n",
2811318507b7Smistachkin                  (int)osGetCurrentProcessId(), pShmNode->nRegion, iOffset,
2812318507b7Smistachkin                  szRegion, pMap ? "ok" : "failed"));
28139785fc95Sdan       }
28149785fc95Sdan       if( !pMap ){
2815318507b7Smistachkin         pShmNode->lastErrno = osGetLastError();
28162aef997cSmistachkin         rc = winLogError(SQLITE_IOERR_SHMMAP, pShmNode->lastErrno,
28172aef997cSmistachkin                  "winShmMap3", pDbFd->zPath);
2818318507b7Smistachkin         if( hMap ) osCloseHandle(hMap);
28199785fc95Sdan         goto shmpage_out;
28209785fc95Sdan       }
28219785fc95Sdan 
28229785fc95Sdan       pShmNode->aRegion[pShmNode->nRegion].pMap = pMap;
28239785fc95Sdan       pShmNode->aRegion[pShmNode->nRegion].hMap = hMap;
28249785fc95Sdan       pShmNode->nRegion++;
28259785fc95Sdan     }
28269785fc95Sdan   }
28279785fc95Sdan 
28289785fc95Sdan shmpage_out:
28299785fc95Sdan   if( pShmNode->nRegion>iRegion ){
2830420398ceSshaneh     int iOffset = iRegion*szRegion;
2831420398ceSshaneh     int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
28329785fc95Sdan     char *p = (char *)pShmNode->aRegion[iRegion].pMap;
2833420398ceSshaneh     *pp = (void *)&p[iOffsetShift];
283483235214Sdrh   }else{
28359785fc95Sdan     *pp = 0;
283683235214Sdrh   }
283783235214Sdrh   sqlite3_mutex_leave(pShmNode->mutex);
283883235214Sdrh   return rc;
283983235214Sdrh }
284083235214Sdrh 
284183235214Sdrh #else
28421f3e27b2Sshaneh # define winShmMap     0
2843da9fe0c3Sdan # define winShmLock    0
2844286a2884Sdrh # define winShmBarrier 0
2845e11fedc5Sdrh # define winShmUnmap   0
284683235214Sdrh #endif /* #ifndef SQLITE_OMIT_WAL */
28471f3e27b2Sshaneh 
284883235214Sdrh /*
28491f3e27b2Sshaneh ** Here ends the implementation of all sqlite3_file methods.
28501f3e27b2Sshaneh **
28511f3e27b2Sshaneh ********************** End sqlite3_file Methods *******************************
28521f3e27b2Sshaneh ******************************************************************************/
285383235214Sdrh 
2854153c62c4Sdrh /*
2855153c62c4Sdrh ** This vector defines all the methods that can operate on an
2856153c62c4Sdrh ** sqlite3_file for win32.
2857153c62c4Sdrh */
2858153c62c4Sdrh static const sqlite3_io_methods winIoMethod = {
285983235214Sdrh   2,                              /* iVersion */
2860da9fe0c3Sdan   winClose,                       /* xClose */
2861da9fe0c3Sdan   winRead,                        /* xRead */
2862da9fe0c3Sdan   winWrite,                       /* xWrite */
2863da9fe0c3Sdan   winTruncate,                    /* xTruncate */
2864da9fe0c3Sdan   winSync,                        /* xSync */
2865da9fe0c3Sdan   winFileSize,                    /* xFileSize */
2866da9fe0c3Sdan   winLock,                        /* xLock */
2867da9fe0c3Sdan   winUnlock,                      /* xUnlock */
2868da9fe0c3Sdan   winCheckReservedLock,           /* xCheckReservedLock */
2869da9fe0c3Sdan   winFileControl,                 /* xFileControl */
2870da9fe0c3Sdan   winSectorSize,                  /* xSectorSize */
2871da9fe0c3Sdan   winDeviceCharacteristics,       /* xDeviceCharacteristics */
28726b017cc6Sdrh   winShmMap,                      /* xShmMap */
2873da9fe0c3Sdan   winShmLock,                     /* xShmLock */
2874286a2884Sdrh   winShmBarrier,                  /* xShmBarrier */
2875e11fedc5Sdrh   winShmUnmap                     /* xShmUnmap */
28769c06c953Sdrh };
28779c06c953Sdrh 
28781f3e27b2Sshaneh /****************************************************************************
28791f3e27b2Sshaneh **************************** sqlite3_vfs methods ****************************
2880153c62c4Sdrh **
28811f3e27b2Sshaneh ** This division contains the implementation of methods on the
28821f3e27b2Sshaneh ** sqlite3_vfs object.
28831f3e27b2Sshaneh */
28840ccebe7eSdrh 
2885153c62c4Sdrh /*
2886153c62c4Sdrh ** Convert a UTF-8 filename into whatever form the underlying
2887153c62c4Sdrh ** operating system wants filenames in.  Space to hold the result
2888b11caac3Sdrh ** is obtained from malloc and must be freed by the calling
2889153c62c4Sdrh ** function.
2890153c62c4Sdrh */
2891153c62c4Sdrh static void *convertUtf8Filename(const char *zFilename){
2892153c62c4Sdrh   void *zConverted = 0;
2893153c62c4Sdrh   if( isNT() ){
2894153c62c4Sdrh     zConverted = utf8ToUnicode(zFilename);
2895891adeacSshane /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
2896891adeacSshane */
2897891adeacSshane #if SQLITE_OS_WINCE==0
2898153c62c4Sdrh   }else{
28995b92f192Sdrh     zConverted = sqlite3_win32_utf8_to_mbcs(zFilename);
2900891adeacSshane #endif
2901153c62c4Sdrh   }
2902153c62c4Sdrh   /* caller will handle out of memory */
2903153c62c4Sdrh   return zConverted;
2904153c62c4Sdrh }
2905153c62c4Sdrh 
2906153c62c4Sdrh /*
290717b90b53Sdanielk1977 ** Create a temporary file name in zBuf.  zBuf must be big enough to
290817b90b53Sdanielk1977 ** hold at pVfs->mxPathname characters.
290917b90b53Sdanielk1977 */
291017b90b53Sdanielk1977 static int getTempname(int nBuf, char *zBuf){
291117b90b53Sdanielk1977   static char zChars[] =
291217b90b53Sdanielk1977     "abcdefghijklmnopqrstuvwxyz"
291317b90b53Sdanielk1977     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
291417b90b53Sdanielk1977     "0123456789";
29153582c5a9Sshane   size_t i, j;
291617b90b53Sdanielk1977   char zTempPath[MAX_PATH+1];
2917e2ad9317Sshaneh 
2918e2ad9317Sshaneh   /* It's odd to simulate an io-error here, but really this is just
2919e2ad9317Sshaneh   ** using the io-error infrastructure to test that SQLite handles this
2920e2ad9317Sshaneh   ** function failing.
2921e2ad9317Sshaneh   */
2922e2ad9317Sshaneh   SimulateIOError( return SQLITE_IOERR );
2923e2ad9317Sshaneh 
292417b90b53Sdanielk1977   if( sqlite3_temp_directory ){
292517b90b53Sdanielk1977     sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory);
292617b90b53Sdanielk1977   }else if( isNT() ){
292717b90b53Sdanielk1977     char *zMulti;
292817b90b53Sdanielk1977     WCHAR zWidePath[MAX_PATH];
2929318507b7Smistachkin     osGetTempPathW(MAX_PATH-30, zWidePath);
293017b90b53Sdanielk1977     zMulti = unicodeToUtf8(zWidePath);
293117b90b53Sdanielk1977     if( zMulti ){
293217b90b53Sdanielk1977       sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti);
29335f075388Smistachkin       sqlite3_free(zMulti);
293417b90b53Sdanielk1977     }else{
29355f075388Smistachkin       return SQLITE_IOERR_NOMEM;
293617b90b53Sdanielk1977     }
2937891adeacSshane /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
29386c3c1a09Smistachkin ** Since the ANSI version of these Windows API do not exist for WINCE,
2939891adeacSshane ** it's important to not reference them for WINCE builds.
2940891adeacSshane */
2941891adeacSshane #if SQLITE_OS_WINCE==0
294217b90b53Sdanielk1977   }else{
294317b90b53Sdanielk1977     char *zUtf8;
294417b90b53Sdanielk1977     char zMbcsPath[MAX_PATH];
2945318507b7Smistachkin     osGetTempPathA(MAX_PATH-30, zMbcsPath);
29461d298855Sdrh     zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath);
294717b90b53Sdanielk1977     if( zUtf8 ){
294817b90b53Sdanielk1977       sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8);
29495f075388Smistachkin       sqlite3_free(zUtf8);
295017b90b53Sdanielk1977     }else{
29515f075388Smistachkin       return SQLITE_IOERR_NOMEM;
295217b90b53Sdanielk1977     }
2953891adeacSshane #endif
295417b90b53Sdanielk1977   }
2955e2ad9317Sshaneh 
2956e2ad9317Sshaneh   /* Check that the output buffer is large enough for the temporary file
2957e2ad9317Sshaneh   ** name. If it is not, return SQLITE_ERROR.
2958e2ad9317Sshaneh   */
2959e2ad9317Sshaneh   if( (sqlite3Strlen30(zTempPath) + sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX) + 17) >= nBuf ){
2960e2ad9317Sshaneh     return SQLITE_ERROR;
2961e2ad9317Sshaneh   }
2962e2ad9317Sshaneh 
2963ea678832Sdrh   for(i=sqlite3Strlen30(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
296417b90b53Sdanielk1977   zTempPath[i] = 0;
2965e2ad9317Sshaneh 
2966e2ad9317Sshaneh   sqlite3_snprintf(nBuf-17, zBuf,
296717b90b53Sdanielk1977                    "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath);
2968ea678832Sdrh   j = sqlite3Strlen30(zBuf);
2969e2ad9317Sshaneh   sqlite3_randomness(15, &zBuf[j]);
2970e2ad9317Sshaneh   for(i=0; i<15; i++, j++){
297117b90b53Sdanielk1977     zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
297217b90b53Sdanielk1977   }
297317b90b53Sdanielk1977   zBuf[j] = 0;
2974e2ad9317Sshaneh 
2975308c2a5cSdrh   OSTRACE(("TEMP FILENAME: %s\n", zBuf));
297617b90b53Sdanielk1977   return SQLITE_OK;
297717b90b53Sdanielk1977 }
297817b90b53Sdanielk1977 
2979820800d0Sshane /*
2980153c62c4Sdrh ** Open a file.
2981153c62c4Sdrh */
2982153c62c4Sdrh static int winOpen(
2983153c62c4Sdrh   sqlite3_vfs *pVfs,        /* Not used */
2984153c62c4Sdrh   const char *zName,        /* Name of the file (UTF-8) */
2985153c62c4Sdrh   sqlite3_file *id,         /* Write the SQLite file handle here */
2986153c62c4Sdrh   int flags,                /* Open mode flags */
2987153c62c4Sdrh   int *pOutFlags            /* Status return flags */
2988153c62c4Sdrh ){
2989153c62c4Sdrh   HANDLE h;
2990d1ef9b6dSmistachkin   DWORD lastErrno;
2991153c62c4Sdrh   DWORD dwDesiredAccess;
2992153c62c4Sdrh   DWORD dwShareMode;
2993153c62c4Sdrh   DWORD dwCreationDisposition;
2994153c62c4Sdrh   DWORD dwFlagsAndAttributes = 0;
2995d94b0556Sshane #if SQLITE_OS_WINCE
2996d94b0556Sshane   int isTemp = 0;
2997d94b0556Sshane #endif
2998153c62c4Sdrh   winFile *pFile = (winFile*)id;
299917b90b53Sdanielk1977   void *zConverted;              /* Filename in OS encoding */
300017b90b53Sdanielk1977   const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */
3001fda06befSmistachkin   int cnt = 0;
3002f7b5f855Sshaneh 
3003f7b5f855Sshaneh   /* If argument zPath is a NULL pointer, this function is required to open
3004f7b5f855Sshaneh   ** a temporary file. Use this buffer to store the file name in.
3005f7b5f855Sshaneh   */
300617b90b53Sdanielk1977   char zTmpname[MAX_PATH+1];     /* Buffer used to create temp filename */
300717b90b53Sdanielk1977 
3008f7b5f855Sshaneh   int rc = SQLITE_OK;            /* Function Return Code */
3009bd2aaf9aSshaneh #if !defined(NDEBUG) || SQLITE_OS_WINCE
3010f7b5f855Sshaneh   int eType = flags&0xFFFFFF00;  /* Type of file to open */
3011bd2aaf9aSshaneh #endif
3012f7b5f855Sshaneh 
3013f7b5f855Sshaneh   int isExclusive  = (flags & SQLITE_OPEN_EXCLUSIVE);
3014f7b5f855Sshaneh   int isDelete     = (flags & SQLITE_OPEN_DELETEONCLOSE);
3015f7b5f855Sshaneh   int isCreate     = (flags & SQLITE_OPEN_CREATE);
3016bd2aaf9aSshaneh #ifndef NDEBUG
3017f7b5f855Sshaneh   int isReadonly   = (flags & SQLITE_OPEN_READONLY);
3018bd2aaf9aSshaneh #endif
3019f7b5f855Sshaneh   int isReadWrite  = (flags & SQLITE_OPEN_READWRITE);
3020f7b5f855Sshaneh 
3021bd2aaf9aSshaneh #ifndef NDEBUG
3022f7b5f855Sshaneh   int isOpenJournal = (isCreate && (
3023f7b5f855Sshaneh         eType==SQLITE_OPEN_MASTER_JOURNAL
3024f7b5f855Sshaneh      || eType==SQLITE_OPEN_MAIN_JOURNAL
3025f7b5f855Sshaneh      || eType==SQLITE_OPEN_WAL
3026f7b5f855Sshaneh   ));
3027bd2aaf9aSshaneh #endif
3028f7b5f855Sshaneh 
3029f7b5f855Sshaneh   /* Check the following statements are true:
3030f7b5f855Sshaneh   **
3031f7b5f855Sshaneh   **   (a) Exactly one of the READWRITE and READONLY flags must be set, and
3032f7b5f855Sshaneh   **   (b) if CREATE is set, then READWRITE must also be set, and
3033f7b5f855Sshaneh   **   (c) if EXCLUSIVE is set, then CREATE must also be set.
3034f7b5f855Sshaneh   **   (d) if DELETEONCLOSE is set, then CREATE must also be set.
3035f7b5f855Sshaneh   */
3036f7b5f855Sshaneh   assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
3037f7b5f855Sshaneh   assert(isCreate==0 || isReadWrite);
3038f7b5f855Sshaneh   assert(isExclusive==0 || isCreate);
3039f7b5f855Sshaneh   assert(isDelete==0 || isCreate);
3040f7b5f855Sshaneh 
3041f7b5f855Sshaneh   /* The main DB, main journal, WAL file and master journal are never
3042f7b5f855Sshaneh   ** automatically deleted. Nor are they ever temporary files.  */
3043f7b5f855Sshaneh   assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
3044f7b5f855Sshaneh   assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
3045f7b5f855Sshaneh   assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
3046f7b5f855Sshaneh   assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
3047f7b5f855Sshaneh 
3048f7b5f855Sshaneh   /* Assert that the upper layer has set one of the "file-type" flags. */
3049f7b5f855Sshaneh   assert( eType==SQLITE_OPEN_MAIN_DB      || eType==SQLITE_OPEN_TEMP_DB
3050f7b5f855Sshaneh        || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
3051f7b5f855Sshaneh        || eType==SQLITE_OPEN_SUBJOURNAL   || eType==SQLITE_OPEN_MASTER_JOURNAL
3052f7b5f855Sshaneh        || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
3053f7b5f855Sshaneh   );
3054f7b5f855Sshaneh 
305550daafc7Sshane   assert( id!=0 );
305618e526c1Sshane   UNUSED_PARAMETER(pVfs);
305718e526c1Sshane 
305804882a9eSshaneh   pFile->h = INVALID_HANDLE_VALUE;
305904882a9eSshaneh 
306017b90b53Sdanielk1977   /* If the second argument to this function is NULL, generate a
306117b90b53Sdanielk1977   ** temporary file name to use
306217b90b53Sdanielk1977   */
306317b90b53Sdanielk1977   if( !zUtf8Name ){
3064f7b5f855Sshaneh     assert(isDelete && !isOpenJournal);
3065f7b5f855Sshaneh     rc = getTempname(MAX_PATH+1, zTmpname);
306617b90b53Sdanielk1977     if( rc!=SQLITE_OK ){
306717b90b53Sdanielk1977       return rc;
306817b90b53Sdanielk1977     }
306917b90b53Sdanielk1977     zUtf8Name = zTmpname;
307017b90b53Sdanielk1977   }
307117b90b53Sdanielk1977 
307217b90b53Sdanielk1977   /* Convert the filename to the system encoding. */
307317b90b53Sdanielk1977   zConverted = convertUtf8Filename(zUtf8Name);
3074153c62c4Sdrh   if( zConverted==0 ){
30755f075388Smistachkin     return SQLITE_IOERR_NOMEM;
3076153c62c4Sdrh   }
3077153c62c4Sdrh 
3078f7b5f855Sshaneh   if( isReadWrite ){
3079153c62c4Sdrh     dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
3080153c62c4Sdrh   }else{
3081153c62c4Sdrh     dwDesiredAccess = GENERIC_READ;
3082153c62c4Sdrh   }
3083f7b5f855Sshaneh 
308468d405e2Sshane   /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is
308568d405e2Sshane   ** created. SQLite doesn't use it to indicate "exclusive access"
308668d405e2Sshane   ** as it is usually understood.
308768d405e2Sshane   */
3088f7b5f855Sshaneh   if( isExclusive ){
308968d405e2Sshane     /* Creates a new file, only if it does not already exist. */
309068d405e2Sshane     /* If the file exists, it fails. */
309168d405e2Sshane     dwCreationDisposition = CREATE_NEW;
3092f7b5f855Sshaneh   }else if( isCreate ){
309368d405e2Sshane     /* Open existing file, or create if it doesn't exist */
3094153c62c4Sdrh     dwCreationDisposition = OPEN_ALWAYS;
3095153c62c4Sdrh   }else{
309668d405e2Sshane     /* Opens a file, only if it exists. */
3097153c62c4Sdrh     dwCreationDisposition = OPEN_EXISTING;
3098153c62c4Sdrh   }
3099f7b5f855Sshaneh 
3100153c62c4Sdrh   dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
3101f7b5f855Sshaneh 
3102f7b5f855Sshaneh   if( isDelete ){
310329bafeabSdanielk1977 #if SQLITE_OS_WINCE
31040cd1ea5eSdrh     dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN;
3105d94b0556Sshane     isTemp = 1;
31060cd1ea5eSdrh #else
3107153c62c4Sdrh     dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY
3108153c62c4Sdrh                                | FILE_ATTRIBUTE_HIDDEN
3109153c62c4Sdrh                                | FILE_FLAG_DELETE_ON_CLOSE;
31100cd1ea5eSdrh #endif
3111153c62c4Sdrh   }else{
3112153c62c4Sdrh     dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
3113153c62c4Sdrh   }
3114496936c8Sdrh   /* Reports from the internet are that performance is always
3115496936c8Sdrh   ** better if FILE_FLAG_RANDOM_ACCESS is used.  Ticket #2699. */
3116d94b0556Sshane #if SQLITE_OS_WINCE
3117496936c8Sdrh   dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
3118d94b0556Sshane #endif
3119f7b5f855Sshaneh 
3120153c62c4Sdrh   if( isNT() ){
3121318507b7Smistachkin     while( (h = osCreateFileW((LPCWSTR)zConverted,
3122153c62c4Sdrh                               dwDesiredAccess,
3123fda06befSmistachkin                               dwShareMode, NULL,
3124153c62c4Sdrh                               dwCreationDisposition,
3125153c62c4Sdrh                               dwFlagsAndAttributes,
3126fda06befSmistachkin                               NULL))==INVALID_HANDLE_VALUE &&
3127d1ef9b6dSmistachkin                               retryIoerr(&cnt, &lastErrno) ){}
3128891adeacSshane /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
31296c3c1a09Smistachkin ** Since the ANSI version of these Windows API do not exist for WINCE,
3130891adeacSshane ** it's important to not reference them for WINCE builds.
3131891adeacSshane */
3132891adeacSshane #if SQLITE_OS_WINCE==0
3133153c62c4Sdrh   }else{
3134318507b7Smistachkin     while( (h = osCreateFileA((LPCSTR)zConverted,
3135153c62c4Sdrh                               dwDesiredAccess,
3136fda06befSmistachkin                               dwShareMode, NULL,
3137153c62c4Sdrh                               dwCreationDisposition,
3138153c62c4Sdrh                               dwFlagsAndAttributes,
3139fda06befSmistachkin                               NULL))==INVALID_HANDLE_VALUE &&
3140d1ef9b6dSmistachkin                               retryIoerr(&cnt, &lastErrno) ){}
3141891adeacSshane #endif
3142153c62c4Sdrh   }
3143f7b5f855Sshaneh 
3144fda06befSmistachkin   logIoerr(cnt);
3145fda06befSmistachkin 
314650f6455fSshaneh   OSTRACE(("OPEN %d %s 0x%lx %s\n",
314750f6455fSshaneh            h, zName, dwDesiredAccess,
314850f6455fSshaneh            h==INVALID_HANDLE_VALUE ? "failed" : "ok"));
3149f7b5f855Sshaneh 
3150153c62c4Sdrh   if( h==INVALID_HANDLE_VALUE ){
3151d1ef9b6dSmistachkin     pFile->lastErrno = lastErrno;
31522aef997cSmistachkin     winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
31535f075388Smistachkin     sqlite3_free(zConverted);
31543051dc1cSdrh     if( isReadWrite && !isExclusive ){
3155a111577bSdrh       return winOpen(pVfs, zName, id,
3156f7b5f855Sshaneh              ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags);
3157153c62c4Sdrh     }else{
31589978c97eSdrh       return SQLITE_CANTOPEN_BKPT;
3159153c62c4Sdrh     }
3160153c62c4Sdrh   }
3161f7b5f855Sshaneh 
3162153c62c4Sdrh   if( pOutFlags ){
3163f7b5f855Sshaneh     if( isReadWrite ){
3164153c62c4Sdrh       *pOutFlags = SQLITE_OPEN_READWRITE;
3165153c62c4Sdrh     }else{
3166153c62c4Sdrh       *pOutFlags = SQLITE_OPEN_READONLY;
3167153c62c4Sdrh     }
3168153c62c4Sdrh   }
3169f7b5f855Sshaneh 
3170153c62c4Sdrh   memset(pFile, 0, sizeof(*pFile));
3171153c62c4Sdrh   pFile->pMethod = &winIoMethod;
3172153c62c4Sdrh   pFile->h = h;
31739db299fbSshane   pFile->lastErrno = NO_ERROR;
317483235214Sdrh   pFile->pVfs = pVfs;
317583235214Sdrh   pFile->pShm = 0;
317683235214Sdrh   pFile->zPath = zName;
317750daafc7Sshane   pFile->sectorSize = getSectorSize(pVfs, zUtf8Name);
3178f7b5f855Sshaneh 
317929bafeabSdanielk1977 #if SQLITE_OS_WINCE
3180f7b5f855Sshaneh   if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
3181aab2e6d2Sdrh        && !winceCreateLock(zName, pFile)
3182153c62c4Sdrh   ){
3183318507b7Smistachkin     osCloseHandle(h);
31845f075388Smistachkin     sqlite3_free(zConverted);
31859978c97eSdrh     return SQLITE_CANTOPEN_BKPT;
3186153c62c4Sdrh   }
3187fc3afb6aSdrh   if( isTemp ){
3188153c62c4Sdrh     pFile->zDeleteOnClose = zConverted;
3189153c62c4Sdrh   }else
3190153c62c4Sdrh #endif
3191153c62c4Sdrh   {
31925f075388Smistachkin     sqlite3_free(zConverted);
3193153c62c4Sdrh   }
3194f7b5f855Sshaneh 
3195af5f0405Sdrh   OpenCounter(+1);
3196f7b5f855Sshaneh   return rc;
3197153c62c4Sdrh }
3198153c62c4Sdrh 
3199153c62c4Sdrh /*
3200153c62c4Sdrh ** Delete the named file.
3201153c62c4Sdrh **
3202318507b7Smistachkin ** Note that Windows does not allow a file to be deleted if some other
3203153c62c4Sdrh ** process has it open.  Sometimes a virus scanner or indexing program
3204153c62c4Sdrh ** will open a journal file shortly after it is created in order to do
32053582c5a9Sshane ** whatever it does.  While this other process is holding the
3206153c62c4Sdrh ** file open, we will be unable to delete it.  To work around this
3207153c62c4Sdrh ** problem, we delay 100 milliseconds and try to delete again.  Up
3208153c62c4Sdrh ** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
3209153c62c4Sdrh ** up and returning an error.
3210153c62c4Sdrh */
3211153c62c4Sdrh static int winDelete(
3212153c62c4Sdrh   sqlite3_vfs *pVfs,          /* Not used on win32 */
3213153c62c4Sdrh   const char *zFilename,      /* Name of file to delete */
3214153c62c4Sdrh   int syncDir                 /* Not used on win32 */
3215153c62c4Sdrh ){
3216153c62c4Sdrh   int cnt = 0;
321752564d70Sdrh   int rc;
3218d1ef9b6dSmistachkin   DWORD lastErrno;
3219e2ad9317Sshaneh   void *zConverted;
322018e526c1Sshane   UNUSED_PARAMETER(pVfs);
322118e526c1Sshane   UNUSED_PARAMETER(syncDir);
3222e2ad9317Sshaneh 
3223e2ad9317Sshaneh   SimulateIOError(return SQLITE_IOERR_DELETE);
3224e2ad9317Sshaneh   zConverted = convertUtf8Filename(zFilename);
3225153c62c4Sdrh   if( zConverted==0 ){
32265f075388Smistachkin     return SQLITE_IOERR_NOMEM;
3227153c62c4Sdrh   }
3228153c62c4Sdrh   if( isNT() ){
3229dc9e9587Smistachkin     rc = 1;
3230318507b7Smistachkin     while( osGetFileAttributesW(zConverted)!=INVALID_FILE_ATTRIBUTES &&
3231d1ef9b6dSmistachkin          (rc = osDeleteFileW(zConverted))==0 && retryIoerr(&cnt, &lastErrno) ){}
3232dc9e9587Smistachkin     rc = rc ? SQLITE_OK : SQLITE_ERROR;
3233891adeacSshane /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
32346c3c1a09Smistachkin ** Since the ANSI version of these Windows API do not exist for WINCE,
3235891adeacSshane ** it's important to not reference them for WINCE builds.
3236891adeacSshane */
3237891adeacSshane #if SQLITE_OS_WINCE==0
3238153c62c4Sdrh   }else{
3239dc9e9587Smistachkin     rc = 1;
3240318507b7Smistachkin     while( osGetFileAttributesA(zConverted)!=INVALID_FILE_ATTRIBUTES &&
3241d1ef9b6dSmistachkin          (rc = osDeleteFileA(zConverted))==0 && retryIoerr(&cnt, &lastErrno) ){}
3242dc9e9587Smistachkin     rc = rc ? SQLITE_OK : SQLITE_ERROR;
3243891adeacSshane #endif
3244153c62c4Sdrh   }
3245a32ad843Sdrh   if( rc ){
3246d1ef9b6dSmistachkin     rc = winLogError(SQLITE_IOERR_DELETE, lastErrno,
32472aef997cSmistachkin              "winDelete", zFilename);
3248a32ad843Sdrh   }else{
3249a32ad843Sdrh     logIoerr(cnt);
3250a32ad843Sdrh   }
32515f075388Smistachkin   sqlite3_free(zConverted);
325252564d70Sdrh   OSTRACE(("DELETE \"%s\" %s\n", zFilename, (rc ? "failed" : "ok" )));
325352564d70Sdrh   return rc;
3254153c62c4Sdrh }
3255153c62c4Sdrh 
3256153c62c4Sdrh /*
3257153c62c4Sdrh ** Check the existance and status of a file.
3258153c62c4Sdrh */
3259153c62c4Sdrh static int winAccess(
3260153c62c4Sdrh   sqlite3_vfs *pVfs,         /* Not used on win32 */
3261153c62c4Sdrh   const char *zFilename,     /* Name of file to check */
3262861f7456Sdanielk1977   int flags,                 /* Type of test to make on this file */
3263861f7456Sdanielk1977   int *pResOut               /* OUT: Result */
3264153c62c4Sdrh ){
3265153c62c4Sdrh   DWORD attr;
3266ea678832Sdrh   int rc = 0;
3267d1ef9b6dSmistachkin   DWORD lastErrno;
3268cce1b689Sshaneh   void *zConverted;
326918e526c1Sshane   UNUSED_PARAMETER(pVfs);
3270cce1b689Sshaneh 
3271cce1b689Sshaneh   SimulateIOError( return SQLITE_IOERR_ACCESS; );
3272cce1b689Sshaneh   zConverted = convertUtf8Filename(zFilename);
3273153c62c4Sdrh   if( zConverted==0 ){
32745f075388Smistachkin     return SQLITE_IOERR_NOMEM;
3275153c62c4Sdrh   }
3276153c62c4Sdrh   if( isNT() ){
3277fdf6db12Sdrh     int cnt = 0;
3278722a7e9aSdrh     WIN32_FILE_ATTRIBUTE_DATA sAttrData;
3279722a7e9aSdrh     memset(&sAttrData, 0, sizeof(sAttrData));
3280318507b7Smistachkin     while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
32817ea72591Sshaneh                              GetFileExInfoStandard,
3282d1ef9b6dSmistachkin                              &sAttrData)) && retryIoerr(&cnt, &lastErrno) ){}
3283fdf6db12Sdrh     if( rc ){
3284722a7e9aSdrh       /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file
3285722a7e9aSdrh       ** as if it does not exist.
3286722a7e9aSdrh       */
32877ea72591Sshaneh       if(    flags==SQLITE_ACCESS_EXISTS
32887ea72591Sshaneh           && sAttrData.nFileSizeHigh==0
32897ea72591Sshaneh           && sAttrData.nFileSizeLow==0 ){
3290722a7e9aSdrh         attr = INVALID_FILE_ATTRIBUTES;
32917ea72591Sshaneh       }else{
32927ea72591Sshaneh         attr = sAttrData.dwFileAttributes;
32937ea72591Sshaneh       }
32947ea72591Sshaneh     }else{
3295e75a717dSmistachkin       logIoerr(cnt);
32962aef997cSmistachkin       if( lastErrno!=ERROR_FILE_NOT_FOUND ){
32972aef997cSmistachkin         winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess", zFilename);
32985f075388Smistachkin         sqlite3_free(zConverted);
3299cce1b689Sshaneh         return SQLITE_IOERR_ACCESS;
3300cce1b689Sshaneh       }else{
3301cce1b689Sshaneh         attr = INVALID_FILE_ATTRIBUTES;
3302cce1b689Sshaneh       }
3303722a7e9aSdrh     }
3304891adeacSshane /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
33056c3c1a09Smistachkin ** Since the ANSI version of these Windows API do not exist for WINCE,
3306891adeacSshane ** it's important to not reference them for WINCE builds.
3307891adeacSshane */
3308891adeacSshane #if SQLITE_OS_WINCE==0
3309153c62c4Sdrh   }else{
3310318507b7Smistachkin     attr = osGetFileAttributesA((char*)zConverted);
3311891adeacSshane #endif
3312153c62c4Sdrh   }
33135f075388Smistachkin   sqlite3_free(zConverted);
3314153c62c4Sdrh   switch( flags ){
331550d3f906Sdrh     case SQLITE_ACCESS_READ:
3316153c62c4Sdrh     case SQLITE_ACCESS_EXISTS:
3317820800d0Sshane       rc = attr!=INVALID_FILE_ATTRIBUTES;
3318153c62c4Sdrh       break;
3319153c62c4Sdrh     case SQLITE_ACCESS_READWRITE:
33204e6b49b4Smistachkin       rc = attr!=INVALID_FILE_ATTRIBUTES &&
33214e6b49b4Smistachkin              (attr & FILE_ATTRIBUTE_READONLY)==0;
3322153c62c4Sdrh       break;
3323153c62c4Sdrh     default:
3324153c62c4Sdrh       assert(!"Invalid flags argument");
3325153c62c4Sdrh   }
3326861f7456Sdanielk1977   *pResOut = rc;
3327861f7456Sdanielk1977   return SQLITE_OK;
3328153c62c4Sdrh }
3329153c62c4Sdrh 
3330153c62c4Sdrh 
3331153c62c4Sdrh /*
3332153c62c4Sdrh ** Turn a relative pathname into a full pathname.  Write the full
3333153c62c4Sdrh ** pathname into zOut[].  zOut[] will be at least pVfs->mxPathname
3334153c62c4Sdrh ** bytes in size.
3335153c62c4Sdrh */
3336153c62c4Sdrh static int winFullPathname(
3337adfb9b05Sdanielk1977   sqlite3_vfs *pVfs,            /* Pointer to vfs object */
3338adfb9b05Sdanielk1977   const char *zRelative,        /* Possibly relative input path */
3339adfb9b05Sdanielk1977   int nFull,                    /* Size of output buffer in bytes */
3340adfb9b05Sdanielk1977   char *zFull                   /* Output buffer */
3341153c62c4Sdrh ){
3342153c62c4Sdrh 
3343153c62c4Sdrh #if defined(__CYGWIN__)
3344e2ad9317Sshaneh   SimulateIOError( return SQLITE_ERROR );
334518e526c1Sshane   UNUSED_PARAMETER(nFull);
3346153c62c4Sdrh   cygwin_conv_to_full_win32_path(zRelative, zFull);
3347076f1c0dSdanielk1977   return SQLITE_OK;
3348153c62c4Sdrh #endif
3349153c62c4Sdrh 
335029bafeabSdanielk1977 #if SQLITE_OS_WINCE
3351e2ad9317Sshaneh   SimulateIOError( return SQLITE_ERROR );
335218e526c1Sshane   UNUSED_PARAMETER(nFull);
3353153c62c4Sdrh   /* WinCE has no concept of a relative pathname, or so I am told. */
3354153c62c4Sdrh   sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zRelative);
3355e825609aSdrh   return SQLITE_OK;
3356153c62c4Sdrh #endif
3357153c62c4Sdrh 
335829bafeabSdanielk1977 #if !SQLITE_OS_WINCE && !defined(__CYGWIN__)
3359153c62c4Sdrh   int nByte;
3360153c62c4Sdrh   void *zConverted;
3361153c62c4Sdrh   char *zOut;
3362e2ad9317Sshaneh 
33634d7a4461Sdan   /* If this path name begins with "/X:", where "X" is any alphabetic
33644d7a4461Sdan   ** character, discard the initial "/" from the pathname.
33654d7a4461Sdan   */
33664d7a4461Sdan   if( zRelative[0]=='/' && sqlite3Isalpha(zRelative[1]) && zRelative[2]==':' ){
33674d7a4461Sdan     zRelative++;
33684d7a4461Sdan   }
33694d7a4461Sdan 
3370e2ad9317Sshaneh   /* It's odd to simulate an io-error here, but really this is just
3371e2ad9317Sshaneh   ** using the io-error infrastructure to test that SQLite handles this
3372e2ad9317Sshaneh   ** function failing. This function could fail if, for example, the
3373e2ad9317Sshaneh   ** current working directory has been unlinked.
3374e2ad9317Sshaneh   */
3375e2ad9317Sshaneh   SimulateIOError( return SQLITE_ERROR );
337618e526c1Sshane   UNUSED_PARAMETER(nFull);
3377153c62c4Sdrh   zConverted = convertUtf8Filename(zRelative);
33785f075388Smistachkin   if( zConverted==0 ){
33795f075388Smistachkin     return SQLITE_IOERR_NOMEM;
33805f075388Smistachkin   }
3381153c62c4Sdrh   if( isNT() ){
3382318507b7Smistachkin     LPWSTR zTemp;
3383318507b7Smistachkin     nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0) + 3;
33845f075388Smistachkin     zTemp = sqlite3_malloc( nByte*sizeof(zTemp[0]) );
3385153c62c4Sdrh     if( zTemp==0 ){
33865f075388Smistachkin       sqlite3_free(zConverted);
33875f075388Smistachkin       return SQLITE_IOERR_NOMEM;
3388153c62c4Sdrh     }
3389318507b7Smistachkin     osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0);
33905f075388Smistachkin     sqlite3_free(zConverted);
3391153c62c4Sdrh     zOut = unicodeToUtf8(zTemp);
33925f075388Smistachkin     sqlite3_free(zTemp);
3393891adeacSshane /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
33946c3c1a09Smistachkin ** Since the ANSI version of these Windows API do not exist for WINCE,
3395891adeacSshane ** it's important to not reference them for WINCE builds.
3396891adeacSshane */
3397891adeacSshane #if SQLITE_OS_WINCE==0
3398153c62c4Sdrh   }else{
3399153c62c4Sdrh     char *zTemp;
3400318507b7Smistachkin     nByte = osGetFullPathNameA((char*)zConverted, 0, 0, 0) + 3;
34015f075388Smistachkin     zTemp = sqlite3_malloc( nByte*sizeof(zTemp[0]) );
3402153c62c4Sdrh     if( zTemp==0 ){
34035f075388Smistachkin       sqlite3_free(zConverted);
34045f075388Smistachkin       return SQLITE_IOERR_NOMEM;
3405153c62c4Sdrh     }
3406318507b7Smistachkin     osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
34075f075388Smistachkin     sqlite3_free(zConverted);
34081d298855Sdrh     zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
34095f075388Smistachkin     sqlite3_free(zTemp);
3410891adeacSshane #endif
3411153c62c4Sdrh   }
3412153c62c4Sdrh   if( zOut ){
3413b11caac3Sdrh     sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zOut);
34145f075388Smistachkin     sqlite3_free(zOut);
3415153c62c4Sdrh     return SQLITE_OK;
3416153c62c4Sdrh   }else{
34175f075388Smistachkin     return SQLITE_IOERR_NOMEM;
3418153c62c4Sdrh   }
3419153c62c4Sdrh #endif
3420153c62c4Sdrh }
3421153c62c4Sdrh 
342250daafc7Sshane /*
342350daafc7Sshane ** Get the sector size of the device used to store
342450daafc7Sshane ** file.
342550daafc7Sshane */
342650daafc7Sshane static int getSectorSize(
342750daafc7Sshane     sqlite3_vfs *pVfs,
342850daafc7Sshane     const char *zRelative     /* UTF-8 file name */
342950daafc7Sshane ){
343050daafc7Sshane   DWORD bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE;
3431d87873d1Sshane   /* GetDiskFreeSpace is not supported under WINCE */
3432d87873d1Sshane #if SQLITE_OS_WINCE
3433d87873d1Sshane   UNUSED_PARAMETER(pVfs);
3434d87873d1Sshane   UNUSED_PARAMETER(zRelative);
3435d87873d1Sshane #else
343650daafc7Sshane   char zFullpath[MAX_PATH+1];
343750daafc7Sshane   int rc;
3438d87873d1Sshane   DWORD dwRet = 0;
3439d87873d1Sshane   DWORD dwDummy;
344050daafc7Sshane 
344150daafc7Sshane   /*
344250daafc7Sshane   ** We need to get the full path name of the file
344350daafc7Sshane   ** to get the drive letter to look up the sector
344450daafc7Sshane   ** size.
344550daafc7Sshane   */
3446e2ad9317Sshaneh   SimulateIOErrorBenign(1);
34476c3c1a09Smistachkin   sqlite3BeginBenignMalloc();
344850daafc7Sshane   rc = winFullPathname(pVfs, zRelative, MAX_PATH, zFullpath);
34496c3c1a09Smistachkin   sqlite3EndBenignMalloc();
3450e2ad9317Sshaneh   SimulateIOErrorBenign(0);
345150daafc7Sshane   if( rc == SQLITE_OK )
345250daafc7Sshane   {
34536c3c1a09Smistachkin     void *zConverted;
34546c3c1a09Smistachkin     sqlite3BeginBenignMalloc();
34556c3c1a09Smistachkin     zConverted = convertUtf8Filename(zFullpath);
34566c3c1a09Smistachkin     sqlite3EndBenignMalloc();
345750daafc7Sshane     if( zConverted ){
345850daafc7Sshane       if( isNT() ){
345950daafc7Sshane         /* trim path to just drive reference */
3460318507b7Smistachkin         LPWSTR p = zConverted;
34617a8537b4Sshane         for(;*p;p++){
34627a8537b4Sshane           if( *p == '\\' ){
34637a8537b4Sshane             *p = '\0';
346450daafc7Sshane             break;
346550daafc7Sshane           }
346650daafc7Sshane         }
3467318507b7Smistachkin         dwRet = osGetDiskFreeSpaceW((LPCWSTR)zConverted,
3468a5dc7f73Schw                                     &dwDummy,
346950daafc7Sshane                                     &bytesPerSector,
3470a5dc7f73Schw                                     &dwDummy,
3471a5dc7f73Schw                                     &dwDummy);
347250daafc7Sshane       }else{
347350daafc7Sshane         /* trim path to just drive reference */
3474ea598927Sshane         char *p = (char *)zConverted;
34757a8537b4Sshane         for(;*p;p++){
34767a8537b4Sshane           if( *p == '\\' ){
34777a8537b4Sshane             *p = '\0';
347850daafc7Sshane             break;
347950daafc7Sshane           }
348050daafc7Sshane         }
3481318507b7Smistachkin         dwRet = osGetDiskFreeSpaceA((char*)zConverted,
3482a5dc7f73Schw                                     &dwDummy,
348350daafc7Sshane                                     &bytesPerSector,
3484a5dc7f73Schw                                     &dwDummy,
3485a5dc7f73Schw                                     &dwDummy);
348650daafc7Sshane       }
34875f075388Smistachkin       sqlite3_free(zConverted);
348850daafc7Sshane     }
348950daafc7Sshane     if( !dwRet ){
349050daafc7Sshane       bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE;
349150daafc7Sshane     }
349250daafc7Sshane   }
3493d87873d1Sshane #endif
349450daafc7Sshane   return (int) bytesPerSector;
349550daafc7Sshane }
349650daafc7Sshane 
3497153c62c4Sdrh #ifndef SQLITE_OMIT_LOAD_EXTENSION
3498761df87eSdrh /*
3499761df87eSdrh ** Interfaces for opening a shared library, finding entry points
3500761df87eSdrh ** within the shared library, and closing the shared library.
3501761df87eSdrh */
3502153c62c4Sdrh /*
3503153c62c4Sdrh ** Interfaces for opening a shared library, finding entry points
3504153c62c4Sdrh ** within the shared library, and closing the shared library.
3505153c62c4Sdrh */
3506153c62c4Sdrh static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
3507761df87eSdrh   HANDLE h;
3508761df87eSdrh   void *zConverted = convertUtf8Filename(zFilename);
35091bd10f8aSdrh   UNUSED_PARAMETER(pVfs);
3510761df87eSdrh   if( zConverted==0 ){
3511761df87eSdrh     return 0;
3512761df87eSdrh   }
3513761df87eSdrh   if( isNT() ){
3514318507b7Smistachkin     h = osLoadLibraryW((LPCWSTR)zConverted);
3515891adeacSshane /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
35166c3c1a09Smistachkin ** Since the ANSI version of these Windows API do not exist for WINCE,
3517891adeacSshane ** it's important to not reference them for WINCE builds.
3518891adeacSshane */
3519891adeacSshane #if SQLITE_OS_WINCE==0
3520761df87eSdrh   }else{
3521318507b7Smistachkin     h = osLoadLibraryA((char*)zConverted);
3522891adeacSshane #endif
3523761df87eSdrh   }
35245f075388Smistachkin   sqlite3_free(zConverted);
3525761df87eSdrh   return (void*)h;
3526761df87eSdrh }
3527153c62c4Sdrh static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
35281bd10f8aSdrh   UNUSED_PARAMETER(pVfs);
3529318507b7Smistachkin   getLastErrorMsg(osGetLastError(), nBuf, zBufOut);
3530153c62c4Sdrh }
3531134c4ff6Sdrh static void (*winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
35321bd10f8aSdrh   UNUSED_PARAMETER(pVfs);
3533318507b7Smistachkin   return (void(*)(void))osGetProcAddressA((HANDLE)pHandle, zSymbol);
3534761df87eSdrh }
3535134c4ff6Sdrh static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
35361bd10f8aSdrh   UNUSED_PARAMETER(pVfs);
3537318507b7Smistachkin   osFreeLibrary((HANDLE)pHandle);
3538761df87eSdrh }
3539153c62c4Sdrh #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
3540153c62c4Sdrh   #define winDlOpen  0
3541153c62c4Sdrh   #define winDlError 0
3542153c62c4Sdrh   #define winDlSym   0
3543153c62c4Sdrh   #define winDlClose 0
3544153c62c4Sdrh #endif
3545153c62c4Sdrh 
3546761df87eSdrh 
35470ccebe7eSdrh /*
3548153c62c4Sdrh ** Write up to nBuf bytes of randomness into zBuf.
3549bbd42a6dSdrh */
3550153c62c4Sdrh static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
3551d1a79312Sdrh   int n = 0;
3552c7b7f1aeSshane   UNUSED_PARAMETER(pVfs);
3553c7b7f1aeSshane #if defined(SQLITE_TEST)
3554c7b7f1aeSshane   n = nBuf;
3555c7b7f1aeSshane   memset(zBuf, 0, nBuf);
3556c7b7f1aeSshane #else
35578674261aSdrh   if( sizeof(SYSTEMTIME)<=nBuf-n ){
3558d1a79312Sdrh     SYSTEMTIME x;
3559318507b7Smistachkin     osGetSystemTime(&x);
3560d1a79312Sdrh     memcpy(&zBuf[n], &x, sizeof(x));
3561d1a79312Sdrh     n += sizeof(x);
3562bbd42a6dSdrh   }
3563d1a79312Sdrh   if( sizeof(DWORD)<=nBuf-n ){
3564318507b7Smistachkin     DWORD pid = osGetCurrentProcessId();
3565d1a79312Sdrh     memcpy(&zBuf[n], &pid, sizeof(pid));
3566d1a79312Sdrh     n += sizeof(pid);
3567d1a79312Sdrh   }
3568d1a79312Sdrh   if( sizeof(DWORD)<=nBuf-n ){
3569318507b7Smistachkin     DWORD cnt = osGetTickCount();
3570d1a79312Sdrh     memcpy(&zBuf[n], &cnt, sizeof(cnt));
3571d1a79312Sdrh     n += sizeof(cnt);
3572d1a79312Sdrh   }
3573d1a79312Sdrh   if( sizeof(LARGE_INTEGER)<=nBuf-n ){
3574d1a79312Sdrh     LARGE_INTEGER i;
3575318507b7Smistachkin     osQueryPerformanceCounter(&i);
3576d1a79312Sdrh     memcpy(&zBuf[n], &i, sizeof(i));
3577d1a79312Sdrh     n += sizeof(i);
3578d1a79312Sdrh   }
3579c7b7f1aeSshane #endif
3580d1a79312Sdrh   return n;
3581153c62c4Sdrh }
3582153c62c4Sdrh 
3583bbd42a6dSdrh 
3584bbd42a6dSdrh /*
3585bbd42a6dSdrh ** Sleep for a little while.  Return the amount of time slept.
3586bbd42a6dSdrh */
3587153c62c4Sdrh static int winSleep(sqlite3_vfs *pVfs, int microsec){
3588318507b7Smistachkin   osSleep((microsec+999)/1000);
35891bd10f8aSdrh   UNUSED_PARAMETER(pVfs);
3590153c62c4Sdrh   return ((microsec+999)/1000)*1000;
3591bbd42a6dSdrh }
3592bbd42a6dSdrh 
3593bbd42a6dSdrh /*
359404882a9eSshaneh ** The following variable, if set to a non-zero value, is interpreted as
359504882a9eSshaneh ** the number of seconds since 1970 and is used to set the result of
359604882a9eSshaneh ** sqlite3OsCurrentTime() during testing.
3597bbd42a6dSdrh */
3598bbd42a6dSdrh #ifdef SQLITE_TEST
359904882a9eSshaneh int sqlite3_current_time = 0;  /* Fake system time in seconds since 1970. */
3600bbd42a6dSdrh #endif
3601bbd42a6dSdrh 
3602bbd42a6dSdrh /*
360304882a9eSshaneh ** Find the current time (in Universal Coordinated Time).  Write into *piNow
360404882a9eSshaneh ** the current time and date as a Julian Day number times 86_400_000.  In
360504882a9eSshaneh ** other words, write into *piNow the number of milliseconds since the Julian
360604882a9eSshaneh ** epoch of noon in Greenwich on November 24, 4714 B.C according to the
360704882a9eSshaneh ** proleptic Gregorian calendar.
360804882a9eSshaneh **
36093170225fSdrh ** On success, return SQLITE_OK.  Return SQLITE_ERROR if the time and date
36103170225fSdrh ** cannot be found.
3611bbd42a6dSdrh */
361204882a9eSshaneh static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
3613bbd42a6dSdrh   /* FILETIME structure is a 64-bit value representing the number of
3614bbd42a6dSdrh      100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
3615bbd42a6dSdrh   */
361604882a9eSshaneh   FILETIME ft;
361704882a9eSshaneh   static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000;
361804882a9eSshaneh #ifdef SQLITE_TEST
361904882a9eSshaneh   static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
362004882a9eSshaneh #endif
3621b08a67a7Sshane   /* 2^32 - to avoid use of LL and warnings in gcc */
3622b08a67a7Sshane   static const sqlite3_int64 max32BitValue =
3623b08a67a7Sshane       (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + (sqlite3_int64)294967296;
36245c905d6eSdrh 
362529bafeabSdanielk1977 #if SQLITE_OS_WINCE
3626cc78fea4Sdrh   SYSTEMTIME time;
3627318507b7Smistachkin   osGetSystemTime(&time);
3628820800d0Sshane   /* if SystemTimeToFileTime() fails, it returns zero. */
3629318507b7Smistachkin   if (!osSystemTimeToFileTime(&time,&ft)){
36303170225fSdrh     return SQLITE_ERROR;
3631820800d0Sshane   }
3632cc78fea4Sdrh #else
3633318507b7Smistachkin   osGetSystemTimeAsFileTime( &ft );
3634cc78fea4Sdrh #endif
363504882a9eSshaneh 
363604882a9eSshaneh   *piNow = winFiletimeEpoch +
363704882a9eSshaneh             ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) +
3638b316cb22Sdrh                (sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000;
363904882a9eSshaneh 
3640bbd42a6dSdrh #ifdef SQLITE_TEST
3641bbd42a6dSdrh   if( sqlite3_current_time ){
364204882a9eSshaneh     *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
3643bbd42a6dSdrh   }
3644bbd42a6dSdrh #endif
364504882a9eSshaneh   UNUSED_PARAMETER(pVfs);
36463170225fSdrh   return SQLITE_OK;
3647bbd42a6dSdrh }
3648bbd42a6dSdrh 
3649820800d0Sshane /*
365004882a9eSshaneh ** Find the current time (in Universal Coordinated Time).  Write the
365104882a9eSshaneh ** current time and date as a Julian Day number into *prNow and
365204882a9eSshaneh ** return 0.  Return 1 if the time and date cannot be found.
365304882a9eSshaneh */
3654134c4ff6Sdrh static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
365504882a9eSshaneh   int rc;
365604882a9eSshaneh   sqlite3_int64 i;
365704882a9eSshaneh   rc = winCurrentTimeInt64(pVfs, &i);
365804882a9eSshaneh   if( !rc ){
365904882a9eSshaneh     *prNow = i/86400000.0;
366004882a9eSshaneh   }
366104882a9eSshaneh   return rc;
366204882a9eSshaneh }
366304882a9eSshaneh 
366404882a9eSshaneh /*
3665820800d0Sshane ** The idea is that this function works like a combination of
3666318507b7Smistachkin ** GetLastError() and FormatMessage() on Windows (or errno and
3667318507b7Smistachkin ** strerror_r() on Unix). After an error is returned by an OS
3668820800d0Sshane ** function, SQLite calls this function with zBuf pointing to
3669820800d0Sshane ** a buffer of nBuf bytes. The OS layer should populate the
3670820800d0Sshane ** buffer with a nul-terminated UTF-8 encoded error message
3671be217793Sshane ** describing the last IO error to have occurred within the calling
3672820800d0Sshane ** thread.
3673820800d0Sshane **
3674820800d0Sshane ** If the error message is too large for the supplied buffer,
3675820800d0Sshane ** it should be truncated. The return value of xGetLastError
3676820800d0Sshane ** is zero if the error message fits in the buffer, or non-zero
3677820800d0Sshane ** otherwise (if the message was truncated). If non-zero is returned,
3678820800d0Sshane ** then it is not necessary to include the nul-terminator character
3679820800d0Sshane ** in the output buffer.
3680820800d0Sshane **
3681820800d0Sshane ** Not supplying an error message will have no adverse effect
3682820800d0Sshane ** on SQLite. It is fine to have an implementation that never
3683820800d0Sshane ** returns an error message:
3684820800d0Sshane **
3685820800d0Sshane **   int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
3686820800d0Sshane **     assert(zBuf[0]=='\0');
3687820800d0Sshane **     return 0;
3688820800d0Sshane **   }
3689820800d0Sshane **
3690820800d0Sshane ** However if an error message is supplied, it will be incorporated
3691820800d0Sshane ** by sqlite into the error message available to the user using
3692820800d0Sshane ** sqlite3_errmsg(), possibly making IO errors easier to debug.
3693820800d0Sshane */
3694bcb97fe9Sdanielk1977 static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
36951bd10f8aSdrh   UNUSED_PARAMETER(pVfs);
3696318507b7Smistachkin   return getLastErrorMsg(osGetLastError(), nBuf, zBuf);
3697bcb97fe9Sdanielk1977 }
3698b4bc7057Sdrh 
3699b4bc7057Sdrh /*
3700c0fa4c5fSdanielk1977 ** Initialize and deinitialize the operating system interface.
370113a68c3fSdanielk1977 */
3702c0fa4c5fSdanielk1977 int sqlite3_os_init(void){
3703153c62c4Sdrh   static sqlite3_vfs winVfs = {
370499ab3b12Sdrh     3,                   /* iVersion */
3705153c62c4Sdrh     sizeof(winFile),     /* szOsFile */
3706153c62c4Sdrh     MAX_PATH,            /* mxPathname */
3707153c62c4Sdrh     0,                   /* pNext */
3708153c62c4Sdrh     "win32",             /* zName */
3709153c62c4Sdrh     0,                   /* pAppData */
3710153c62c4Sdrh     winOpen,             /* xOpen */
3711153c62c4Sdrh     winDelete,           /* xDelete */
3712153c62c4Sdrh     winAccess,           /* xAccess */
3713153c62c4Sdrh     winFullPathname,     /* xFullPathname */
3714153c62c4Sdrh     winDlOpen,           /* xDlOpen */
3715153c62c4Sdrh     winDlError,          /* xDlError */
3716153c62c4Sdrh     winDlSym,            /* xDlSym */
3717153c62c4Sdrh     winDlClose,          /* xDlClose */
3718153c62c4Sdrh     winRandomness,       /* xRandomness */
3719153c62c4Sdrh     winSleep,            /* xSleep */
3720bcb97fe9Sdanielk1977     winCurrentTime,      /* xCurrentTime */
3721af75c869Sdrh     winGetLastError,     /* xGetLastError */
372204882a9eSshaneh     winCurrentTimeInt64, /* xCurrentTimeInt64 */
3723318507b7Smistachkin     winSetSystemCall,    /* xSetSystemCall */
3724318507b7Smistachkin     winGetSystemCall,    /* xGetSystemCall */
3725318507b7Smistachkin     winNextSystemCall,   /* xNextSystemCall */
3726153c62c4Sdrh   };
3727e1ab2193Sdan 
3728318507b7Smistachkin   /* Double-check that the aSyscall[] array has been constructed
3729318507b7Smistachkin   ** correctly.  See ticket [bb3a86e890c8e96ab] */
3730318507b7Smistachkin   assert( ArraySize(aSyscall)==60 );
3731318507b7Smistachkin 
3732420398ceSshaneh #ifndef SQLITE_OMIT_WAL
3733420398ceSshaneh   /* get memory map allocation granularity */
3734420398ceSshaneh   memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
3735318507b7Smistachkin   osGetSystemInfo(&winSysInfo);
3736420398ceSshaneh   assert(winSysInfo.dwAllocationGranularity > 0);
3737420398ceSshaneh #endif
3738420398ceSshaneh 
3739c0fa4c5fSdanielk1977   sqlite3_vfs_register(&winVfs, 1);
3740c0fa4c5fSdanielk1977   return SQLITE_OK;
374113a68c3fSdanielk1977 }
37426c3c1a09Smistachkin 
3743c0fa4c5fSdanielk1977 int sqlite3_os_end(void){
3744c0fa4c5fSdanielk1977   return SQLITE_OK;
3745c0fa4c5fSdanielk1977 }
374640257ffdSdrh 
374729bafeabSdanielk1977 #endif /* SQLITE_OS_WIN */
3748