Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: c7c923e7744241023cfef7ea1d0e0f7008bf6ab7 [file] [log] [blame]
drhbbd42a62004-05-22 17:41:581/*
2** 2004 May 22
3**
4** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
6**
7** May you do good and not evil.
8** May you find forgiveness for yourself and forgive others.
9** May you share freely, never taking more than you give.
10**
11******************************************************************************
12**
mistachkin318507b2011-11-11 22:08:5413** This file contains code that is specific to Windows.
drhbbd42a62004-05-22 17:41:5814*/
drhbbd42a62004-05-22 17:41:5815#include "sqliteInt.h"
mistachkin318507b2011-11-11 22:08:5416#if SQLITE_OS_WIN /* This file is used for Windows only */
drhbbd42a62004-05-22 17:41:5817
drhbbd42a62004-05-22 17:41:5818/*
drhbbd42a62004-05-22 17:41:5819** Include code that is common to all os_*.c files
20*/
21#include "os_common.h"
22
23/*
mistachkin8bc52622013-11-25 09:36:0724** Include the header file for the Windows VFS.
25*/
26#include "os_win.h"
27
28/*
mistachkinc60941f2012-09-13 01:51:0229** Compiling and using WAL mode requires several APIs that are only
30** available in Windows platforms based on the NT kernel.
mistachkinf4f327c2012-03-13 03:35:0731*/
mistachkinc60941f2012-09-13 01:51:0232#if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_WAL)
mistachkin4496a232013-08-26 23:18:5733# error "WAL mode requires support from the Windows NT kernel, compile\
mistachkinc60941f2012-09-13 01:51:0234 with SQLITE_OMIT_WAL."
mistachkinf4f327c2012-03-13 03:35:0735#endif
36
mistachkin73767822014-11-04 19:37:2237#if !SQLITE_OS_WINNT && SQLITE_MAX_MMAP_SIZE>0
38# error "Memory mapped files require support from the Windows NT kernel,\
39 compile with SQLITE_MAX_MMAP_SIZE=0."
40#endif
41
mistachkinf4f327c2012-03-13 03:35:0742/*
mistachkinf1dacbf2012-10-07 00:52:2243** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions
44** based on the sub-platform)?
45*/
mistachkin28159a52013-08-31 17:01:5646#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(SQLITE_WIN32_NO_ANSI)
mistachkinf1dacbf2012-10-07 00:52:2247# define SQLITE_WIN32_HAS_ANSI
48#endif
49
50/*
51** Are most of the Win32 Unicode APIs available (i.e. with certain exceptions
52** based on the sub-platform)?
53*/
mistachkin28159a52013-08-31 17:01:5654#if (SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT) && \
55 !defined(SQLITE_WIN32_NO_WIDE)
mistachkinf1dacbf2012-10-07 00:52:2256# define SQLITE_WIN32_HAS_WIDE
57#endif
58
59/*
mistachkin28159a52013-08-31 17:01:5660** Make sure at least one set of Win32 APIs is available.
61*/
62#if !defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_WIN32_HAS_WIDE)
63# error "At least one of SQLITE_WIN32_HAS_ANSI and SQLITE_WIN32_HAS_WIDE\
64 must be defined."
65#endif
66
67/*
mistachkin0f7e08e2013-11-27 03:01:3468** Define the required Windows SDK version constants if they are not
69** already available.
70*/
71#ifndef NTDDI_WIN8
72# define NTDDI_WIN8 0x06020000
73#endif
74
75#ifndef NTDDI_WINBLUE
76# define NTDDI_WINBLUE 0x06030000
77#endif
78
mistachkind5be6f02016-01-27 07:28:3379#ifndef NTDDI_WINTHRESHOLD
80# define NTDDI_WINTHRESHOLD 0x06040000
81#endif
82
mistachkin0f7e08e2013-11-27 03:01:3483/*
drhc96c7e32014-08-11 17:40:3084** Check to see if the GetVersionEx[AW] functions are deprecated on the
drhe5e20d32014-08-11 17:41:5385** target system. GetVersionEx was first deprecated in Win8.1.
mistachkin0f7e08e2013-11-27 03:01:3486*/
87#ifndef SQLITE_WIN32_GETVERSIONEX
88# if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINBLUE
drhc96c7e32014-08-11 17:40:3089# define SQLITE_WIN32_GETVERSIONEX 0 /* GetVersionEx() is deprecated */
mistachkin0f7e08e2013-11-27 03:01:3490# else
drhc96c7e32014-08-11 17:40:3091# define SQLITE_WIN32_GETVERSIONEX 1 /* GetVersionEx() is current */
mistachkin0f7e08e2013-11-27 03:01:3492# endif
93#endif
94
95/*
mistachkind5be6f02016-01-27 07:28:3396** Check to see if the CreateFileMappingA function is supported on the
97** target system. It is unavailable when using "mincore.lib" on Win10.
98** When compiling for Windows 10, always assume "mincore.lib" is in use.
99*/
100#ifndef SQLITE_WIN32_CREATEFILEMAPPINGA
101# if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINTHRESHOLD
102# define SQLITE_WIN32_CREATEFILEMAPPINGA 0
103# else
104# define SQLITE_WIN32_CREATEFILEMAPPINGA 1
105# endif
106#endif
107
108/*
mistachkin9858bf22013-11-09 23:55:18109** This constant should already be defined (in the "WinDef.h" SDK file).
110*/
111#ifndef MAX_PATH
112# define MAX_PATH (260)
113#endif
114
115/*
mistachkin31706a22013-08-26 20:45:50116** Maximum pathname length (in chars) for Win32. This should normally be
117** MAX_PATH.
118*/
119#ifndef SQLITE_WIN32_MAX_PATH_CHARS
120# define SQLITE_WIN32_MAX_PATH_CHARS (MAX_PATH)
121#endif
122
123/*
mistachkin9858bf22013-11-09 23:55:18124** This constant should already be defined (in the "WinNT.h" SDK file).
125*/
126#ifndef UNICODE_STRING_MAX_CHARS
127# define UNICODE_STRING_MAX_CHARS (32767)
128#endif
129
130/*
mistachkin4496a232013-08-26 23:18:57131** Maximum pathname length (in chars) for WinNT. This should normally be
mistachkindc7b0552013-11-09 21:11:36132** UNICODE_STRING_MAX_CHARS.
mistachkin4496a232013-08-26 23:18:57133*/
134#ifndef SQLITE_WINNT_MAX_PATH_CHARS
mistachkindc7b0552013-11-09 21:11:36135# define SQLITE_WINNT_MAX_PATH_CHARS (UNICODE_STRING_MAX_CHARS)
mistachkin4496a232013-08-26 23:18:57136#endif
137
138/*
mistachkine49d98f2013-08-24 23:55:01139** Maximum pathname length (in bytes) for Win32. The MAX_PATH macro is in
mistachkin08046492013-11-10 00:03:11140** characters, so we allocate 4 bytes per character assuming worst-case of
mistachkin4496a232013-08-26 23:18:57141** 4-bytes-per-character for UTF8.
mistachkine49d98f2013-08-24 23:55:01142*/
mistachkin31706a22013-08-26 20:45:50143#ifndef SQLITE_WIN32_MAX_PATH_BYTES
mistachkin4496a232013-08-26 23:18:57144# define SQLITE_WIN32_MAX_PATH_BYTES (SQLITE_WIN32_MAX_PATH_CHARS*4)
145#endif
146
147/*
148** Maximum pathname length (in bytes) for WinNT. This should normally be
mistachkindc7b0552013-11-09 21:11:36149** UNICODE_STRING_MAX_CHARS * sizeof(WCHAR).
mistachkin4496a232013-08-26 23:18:57150*/
151#ifndef SQLITE_WINNT_MAX_PATH_BYTES
152# define SQLITE_WINNT_MAX_PATH_BYTES \
153 (sizeof(WCHAR) * SQLITE_WINNT_MAX_PATH_CHARS)
mistachkine49d98f2013-08-24 23:55:01154#endif
155
156/*
mistachkin31706a22013-08-26 20:45:50157** Maximum error message length (in chars) for WinRT.
mistachkine49d98f2013-08-24 23:55:01158*/
mistachkin31706a22013-08-26 20:45:50159#ifndef SQLITE_WIN32_MAX_ERRMSG_CHARS
160# define SQLITE_WIN32_MAX_ERRMSG_CHARS (1024)
mistachkine49d98f2013-08-24 23:55:01161#endif
162
163/*
mistachkin533fb6d2013-08-28 02:26:48164** Returns non-zero if the character should be treated as a directory
165** separator.
166*/
167#ifndef winIsDirSep
168# define winIsDirSep(a) (((a) == '/') || ((a) == '\\'))
169#endif
170
171/*
mistachkin36ca5352013-09-12 01:47:57172** This macro is used when a local variable is set to a value that is
173** [sometimes] not used by the code (e.g. via conditional compilation).
174*/
175#ifndef UNUSED_VARIABLE_VALUE
mistachkin91d12492014-08-11 17:38:38176# define UNUSED_VARIABLE_VALUE(x) (void)(x)
mistachkin36ca5352013-09-12 01:47:57177#endif
178
179/*
mistachkin14eca4e2013-11-07 22:11:55180** Returns the character that should be used as the directory separator.
mistachkin533fb6d2013-08-28 02:26:48181*/
mistachkin14eca4e2013-11-07 22:11:55182#ifndef winGetDirSep
183# define winGetDirSep() '\\'
mistachkin533fb6d2013-08-28 02:26:48184#endif
185
186/*
mistachkinf1dacbf2012-10-07 00:52:22187** Do we need to manually define the Win32 file mapping APIs for use with WAL
mistachkin73767822014-11-04 19:37:22188** mode or memory mapped files (e.g. these APIs are available in the Windows
189** CE SDK; however, they are not present in the header file)?
mistachkinf1dacbf2012-10-07 00:52:22190*/
mistachkin73767822014-11-04 19:37:22191#if SQLITE_WIN32_FILEMAPPING_API && \
192 (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
mistachkinf1dacbf2012-10-07 00:52:22193/*
194** Two of the file mapping APIs are different under WinRT. Figure out which
195** set we need.
196*/
197#if SQLITE_OS_WINRT
mistachkin31d72112012-10-08 14:36:42198WINBASEAPI HANDLE WINAPI CreateFileMappingFromApp(HANDLE, \
199 LPSECURITY_ATTRIBUTES, ULONG, ULONG64, LPCWSTR);
mistachkinf1dacbf2012-10-07 00:52:22200
mistachkin31d72112012-10-08 14:36:42201WINBASEAPI LPVOID WINAPI MapViewOfFileFromApp(HANDLE, ULONG, ULONG64, SIZE_T);
mistachkinf1dacbf2012-10-07 00:52:22202#else
203#if defined(SQLITE_WIN32_HAS_ANSI)
mistachkin31d72112012-10-08 14:36:42204WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE, LPSECURITY_ATTRIBUTES, \
205 DWORD, DWORD, DWORD, LPCSTR);
mistachkinf1dacbf2012-10-07 00:52:22206#endif /* defined(SQLITE_WIN32_HAS_ANSI) */
207
208#if defined(SQLITE_WIN32_HAS_WIDE)
mistachkin31d72112012-10-08 14:36:42209WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE, LPSECURITY_ATTRIBUTES, \
210 DWORD, DWORD, DWORD, LPCWSTR);
mistachkinf1dacbf2012-10-07 00:52:22211#endif /* defined(SQLITE_WIN32_HAS_WIDE) */
212
mistachkin31d72112012-10-08 14:36:42213WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T);
mistachkinf1dacbf2012-10-07 00:52:22214#endif /* SQLITE_OS_WINRT */
215
216/*
mistachkinccb43712015-03-26 23:36:35217** These file mapping APIs are common to both Win32 and WinRT.
mistachkinf1dacbf2012-10-07 00:52:22218*/
mistachkinccb43712015-03-26 23:36:35219
220WINBASEAPI BOOL WINAPI FlushViewOfFile(LPCVOID, SIZE_T);
mistachkin31d72112012-10-08 14:36:42221WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID);
mistachkin73767822014-11-04 19:37:22222#endif /* SQLITE_WIN32_FILEMAPPING_API */
mistachkinf1dacbf2012-10-07 00:52:22223
224/*
mistachkin318507b2011-11-11 22:08:54225** Some Microsoft compilers lack this definition.
shane171fa292008-09-01 22:15:18226*/
227#ifndef INVALID_FILE_ATTRIBUTES
mistachkin17835a52014-08-06 03:06:01228# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
shane171fa292008-09-01 22:15:18229#endif
230
mistachkin5483f772012-03-07 20:11:47231#ifndef FILE_FLAG_MASK
232# define FILE_FLAG_MASK (0xFF3C0000)
233#endif
234
235#ifndef FILE_ATTRIBUTE_MASK
236# define FILE_ATTRIBUTE_MASK (0x0003FFF7)
237#endif
238
mistachkin6f928332012-08-17 11:47:32239#ifndef SQLITE_OMIT_WAL
mistachkind95a3d32013-08-30 21:52:38240/* Forward references to structures used for WAL */
drh83235212010-05-14 16:34:34241typedef struct winShm winShm; /* A connection to shared-memory */
242typedef struct winShmNode winShmNode; /* A region of shared-memory */
mistachkin6f928332012-08-17 11:47:32243#endif
drh83235212010-05-14 16:34:34244
drhcc78fea2006-01-06 16:17:05245/*
drh72aead82006-01-23 15:54:25246** WinCE lacks native support for file locking so we have to fake it
247** with some code of our own.
248*/
danielk197729bafea2008-06-26 10:41:19249#if SQLITE_OS_WINCE
drh72aead82006-01-23 15:54:25250typedef struct winceLock {
251 int nReaders; /* Number of reader locks obtained */
252 BOOL bPending; /* Indicates a pending lock has been obtained */
253 BOOL bReserved; /* Indicates a reserved lock has been obtained */
254 BOOL bExclusive; /* Indicates an exclusive lock has been obtained */
255} winceLock;
256#endif
257
258/*
drh153c62c2007-08-24 03:51:33259** The winFile structure is a subclass of sqlite3_file* specific to the win32
drh054889e2005-11-30 03:20:31260** portability layer.
drh9cbe6352005-11-29 03:13:21261*/
drh054889e2005-11-30 03:20:31262typedef struct winFile winFile;
263struct winFile {
drh83235212010-05-14 16:34:34264 const sqlite3_io_methods *pMethod; /*** Must be first ***/
265 sqlite3_vfs *pVfs; /* The VFS used to open this file */
drh9cbe6352005-11-29 03:13:21266 HANDLE h; /* Handle for accessing the file */
drhf0b190d2011-07-26 16:03:07267 u8 locktype; /* Type of lock currently held on this file */
drh9cbe6352005-11-29 03:13:21268 short sharedLockByte; /* Randomly chosen byte used as a shared lock */
drhf12b3f62011-12-21 14:42:29269 u8 ctrlFlags; /* Flags. See WINFILE_* below */
shane9db299f2009-01-30 05:59:10270 DWORD lastErrno; /* The Windows errno from the last I/O error */
mistachkin6f928332012-08-17 11:47:32271#ifndef SQLITE_OMIT_WAL
drh83235212010-05-14 16:34:34272 winShm *pShm; /* Instance of shared memory on this file */
mistachkin6f928332012-08-17 11:47:32273#endif
drh83235212010-05-14 16:34:34274 const char *zPath; /* Full pathname of this file */
dan502019c2010-07-28 14:26:17275 int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */
danielk197729bafea2008-06-26 10:41:19276#if SQLITE_OS_WINCE
mistachkin318507b2011-11-11 22:08:54277 LPWSTR zDeleteOnClose; /* Name of file to delete when closing */
mistachkin17835a52014-08-06 03:06:01278 HANDLE hMutex; /* Mutex used to control access to shared lock */
drh72aead82006-01-23 15:54:25279 HANDLE hShared; /* Shared memory segment used for locking */
280 winceLock local; /* Locks obtained by this instance of winFile */
281 winceLock *shared; /* Global shared lock memory for the file */
drhcc78fea2006-01-06 16:17:05282#endif
mistachkin5824e052013-04-15 20:08:27283#if SQLITE_MAX_MMAP_SIZE>0
drh9b4c59f2013-04-15 17:03:42284 int nFetchOut; /* Number of outstanding xFetch references */
285 HANDLE hMap; /* Handle for accessing memory mapping */
286 void *pMapRegion; /* Area memory mapped */
drh48ea97e2018-11-24 16:07:21287 sqlite3_int64 mmapSize; /* Size of mapped region */
drh9b4c59f2013-04-15 17:03:42288 sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
mistachkin5824e052013-04-15 20:08:27289#endif
dan6bd3faa2024-11-22 21:24:08290#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
dan46288882025-01-30 15:26:16291 DWORD iBusyTimeout; /* Wait this many millisec on locks */
dan2d878942025-02-10 20:46:14292 int bBlockOnConnect;
dan6bd3faa2024-11-22 21:24:08293#endif
drh9cbe6352005-11-29 03:13:21294};
295
dand50eb9c2024-12-10 19:00:07296#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
297# define winFileBusyTimeout(pDbFd) pDbFd->iBusyTimeout
298#else
299# define winFileBusyTimeout(pDbFd) 0
300#endif
301
mistachkin1b186a92011-08-24 16:13:57302/*
mistachkin1e754832016-07-08 21:14:37303** The winVfsAppData structure is used for the pAppData member for all of the
304** Win32 VFS variants.
305*/
306typedef struct winVfsAppData winVfsAppData;
307struct winVfsAppData {
308 const sqlite3_io_methods *pMethod; /* The file I/O methods to use. */
309 void *pAppData; /* The extra pAppData, if any. */
310 BOOL bNoLock; /* Non-zero if locking is disabled. */
311};
312
313/*
drhf12b3f62011-12-21 14:42:29314** Allowed values for winFile.ctrlFlags
315*/
mistachkindaf9a5a2013-03-23 09:56:39316#define WINFILE_RDONLY 0x02 /* Connection is read only */
drhf12b3f62011-12-21 14:42:29317#define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */
drhcb15f352011-12-23 01:04:17318#define WINFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
drhf12b3f62011-12-21 14:42:29319
320/*
mistachkinf4f327c2012-03-13 03:35:07321 * The size of the buffer used by sqlite3_win32_write_debug().
322 */
323#ifndef SQLITE_WIN32_DBG_BUF_SIZE
mistachkin16afb9e2012-03-14 23:08:59324# define SQLITE_WIN32_DBG_BUF_SIZE ((int)(4096-sizeof(DWORD)))
mistachkinf4f327c2012-03-13 03:35:07325#endif
326
327/*
mistachkin1b186a92011-08-24 16:13:57328 * If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the
329 * various Win32 API heap functions instead of our own.
330 */
331#ifdef SQLITE_WIN32_MALLOC
mistachkin40c471d2012-03-15 03:40:59332
333/*
334 * If this is non-zero, an isolated heap will be created by the native Win32
335 * allocator subsystem; otherwise, the default process heap will be used. This
336 * setting has no effect when compiling for WinRT. By default, this is enabled
337 * and an isolated heap will be created to store all allocated data.
338 *
339 ******************************************************************************
340 * WARNING: It is important to note that when this setting is non-zero and the
341 * winMemShutdown function is called (e.g. by the sqlite3_shutdown
342 * function), all data that was allocated using the isolated heap will
343 * be freed immediately and any attempt to access any of that freed
344 * data will almost certainly result in an immediate access violation.
345 ******************************************************************************
346 */
347#ifndef SQLITE_WIN32_HEAP_CREATE
mistachkin5e6710a2017-02-20 19:13:37348# define SQLITE_WIN32_HEAP_CREATE (TRUE)
349#endif
350
351/*
352 * This is the maximum possible initial size of the Win32-specific heap, in
353 * bytes.
354 */
355#ifndef SQLITE_WIN32_HEAP_MAX_INIT_SIZE
356# define SQLITE_WIN32_HEAP_MAX_INIT_SIZE (4294967295U)
357#endif
358
359/*
360 * This is the extra space for the initial size of the Win32-specific heap,
361 * in bytes. This value may be zero.
362 */
363#ifndef SQLITE_WIN32_HEAP_INIT_EXTRA
364# define SQLITE_WIN32_HEAP_INIT_EXTRA (4194304)
365#endif
366
367/*
368 * Calculate the maximum legal cache size, in pages, based on the maximum
369 * possible initial heap size and the default page size, setting aside the
370 * needed extra space.
371 */
372#ifndef SQLITE_WIN32_MAX_CACHE_SIZE
373# define SQLITE_WIN32_MAX_CACHE_SIZE (((SQLITE_WIN32_HEAP_MAX_INIT_SIZE) - \
374 (SQLITE_WIN32_HEAP_INIT_EXTRA)) / \
375 (SQLITE_DEFAULT_PAGE_SIZE))
mistachkin40c471d2012-03-15 03:40:59376#endif
377
mistachkin1b186a92011-08-24 16:13:57378/*
mistachkineb2329b2016-03-24 20:36:47379 * This is cache size used in the calculation of the initial size of the
380 * Win32-specific heap. It cannot be negative.
381 */
382#ifndef SQLITE_WIN32_CACHE_SIZE
383# if SQLITE_DEFAULT_CACHE_SIZE>=0
mistachkin5e6710a2017-02-20 19:13:37384# define SQLITE_WIN32_CACHE_SIZE (SQLITE_DEFAULT_CACHE_SIZE)
mistachkineb2329b2016-03-24 20:36:47385# else
mistachkin5e6710a2017-02-20 19:13:37386# define SQLITE_WIN32_CACHE_SIZE (-(SQLITE_DEFAULT_CACHE_SIZE))
mistachkineb2329b2016-03-24 20:36:47387# endif
388#endif
389
390/*
mistachkin5e6710a2017-02-20 19:13:37391 * Make sure that the calculated cache size, in pages, cannot cause the
392 * initial size of the Win32-specific heap to exceed the maximum amount
393 * of memory that can be specified in the call to HeapCreate.
394 */
mistachkin46899562017-02-20 23:32:04395#if SQLITE_WIN32_CACHE_SIZE>SQLITE_WIN32_MAX_CACHE_SIZE
mistachkin5e6710a2017-02-20 19:13:37396# undef SQLITE_WIN32_CACHE_SIZE
397# define SQLITE_WIN32_CACHE_SIZE (2000)
398#endif
399
400/*
mistachkin1b186a92011-08-24 16:13:57401 * The initial size of the Win32-specific heap. This value may be zero.
402 */
403#ifndef SQLITE_WIN32_HEAP_INIT_SIZE
mistachkin5e6710a2017-02-20 19:13:37404# define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_WIN32_CACHE_SIZE) * \
405 (SQLITE_DEFAULT_PAGE_SIZE) + \
406 (SQLITE_WIN32_HEAP_INIT_EXTRA))
mistachkin1b186a92011-08-24 16:13:57407#endif
408
409/*
410 * The maximum size of the Win32-specific heap. This value may be zero.
411 */
412#ifndef SQLITE_WIN32_HEAP_MAX_SIZE
mistachkin5e6710a2017-02-20 19:13:37413# define SQLITE_WIN32_HEAP_MAX_SIZE (0)
mistachkin1b186a92011-08-24 16:13:57414#endif
415
416/*
mistachkin155892c2011-08-26 01:32:24417 * The extra flags to use in calls to the Win32 heap APIs. This value may be
418 * zero for the default behavior.
419 */
420#ifndef SQLITE_WIN32_HEAP_FLAGS
mistachkin5e6710a2017-02-20 19:13:37421# define SQLITE_WIN32_HEAP_FLAGS (0)
mistachkin155892c2011-08-26 01:32:24422#endif
423
drh68f7a9e2013-07-31 19:55:25424
mistachkin155892c2011-08-26 01:32:24425/*
mistachkin1b186a92011-08-24 16:13:57426** The winMemData structure stores information required by the Win32-specific
427** sqlite3_mem_methods implementation.
428*/
429typedef struct winMemData winMemData;
430struct winMemData {
mistachkin7da32b52011-08-26 01:45:50431#ifndef NDEBUG
mistachkine8f91052013-11-08 18:13:48432 u32 magic1; /* Magic number to detect structure corruption. */
mistachkin7da32b52011-08-26 01:45:50433#endif
mistachkin1b186a92011-08-24 16:13:57434 HANDLE hHeap; /* The handle to our heap. */
435 BOOL bOwned; /* Do we own the heap (i.e. destroy it on shutdown)? */
mistachkine8f91052013-11-08 18:13:48436#ifndef NDEBUG
437 u32 magic2; /* Magic number to detect structure corruption. */
438#endif
mistachkin1b186a92011-08-24 16:13:57439};
440
mistachkin7da32b52011-08-26 01:45:50441#ifndef NDEBUG
mistachkine8f91052013-11-08 18:13:48442#define WINMEM_MAGIC1 0x42b2830b
443#define WINMEM_MAGIC2 0xbd4d7cf4
mistachkin7da32b52011-08-26 01:45:50444#endif
mistachkin1b186a92011-08-24 16:13:57445
mistachkin7da32b52011-08-26 01:45:50446static struct winMemData win_mem_data = {
447#ifndef NDEBUG
mistachkine8f91052013-11-08 18:13:48448 WINMEM_MAGIC1,
mistachkin7da32b52011-08-26 01:45:50449#endif
450 NULL, FALSE
mistachkine8f91052013-11-08 18:13:48451#ifndef NDEBUG
452 ,WINMEM_MAGIC2
453#endif
mistachkin7da32b52011-08-26 01:45:50454};
mistachkin1b186a92011-08-24 16:13:57455
mistachkin7da32b52011-08-26 01:45:50456#ifndef NDEBUG
mistachkine8f91052013-11-08 18:13:48457#define winMemAssertMagic1() assert( win_mem_data.magic1==WINMEM_MAGIC1 )
458#define winMemAssertMagic2() assert( win_mem_data.magic2==WINMEM_MAGIC2 )
459#define winMemAssertMagic() winMemAssertMagic1(); winMemAssertMagic2();
mistachkin7da32b52011-08-26 01:45:50460#else
461#define winMemAssertMagic()
462#endif
463
mistachkine8f91052013-11-08 18:13:48464#define winMemGetDataPtr() &win_mem_data
465#define winMemGetHeap() win_mem_data.hHeap
466#define winMemGetOwned() win_mem_data.bOwned
mistachkin468690e2011-08-24 17:42:22467
mistachkin1b186a92011-08-24 16:13:57468static void *winMemMalloc(int nBytes);
469static void winMemFree(void *pPrior);
470static void *winMemRealloc(void *pPrior, int nBytes);
471static int winMemSize(void *p);
472static int winMemRoundup(int n);
473static int winMemInit(void *pAppData);
474static void winMemShutdown(void *pAppData);
475
476const sqlite3_mem_methods *sqlite3MemGetWin32(void);
477#endif /* SQLITE_WIN32_MALLOC */
drh50990db2011-04-13 20:26:13478
shane50daafc2009-03-05 05:54:55479/*
drhc0929982005-09-05 19:08:29480** The following variable is (normally) set once and never changes
mistachkin6c3c1a02011-11-12 03:17:40481** thereafter. It records whether the operating system is Win9x
drhc0929982005-09-05 19:08:29482** or WinNT.
483**
484** 0: Operating system unknown.
mistachkin6c3c1a02011-11-12 03:17:40485** 1: Operating system is Win9x.
drhc0929982005-09-05 19:08:29486** 2: Operating system is WinNT.
487**
488** In order to facilitate testing on a WinNT system, the test fixture
489** can manually set this value to 1 to emulate Win98 behavior.
490*/
drh153c62c2007-08-24 03:51:33491#ifdef SQLITE_TEST
mistachkince64d612014-08-14 18:31:56492LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0;
mistachkin16d511a2014-08-02 20:44:13493#else
mistachkince64d612014-08-14 18:31:56494static LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0;
drh153c62c2007-08-24 03:51:33495#endif
drhc0929982005-09-05 19:08:29496
mistachkin318507b2011-11-11 22:08:54497#ifndef SYSCALL
498# define SYSCALL sqlite3_syscall_ptr
499#endif
500
drh7acec682012-03-01 21:19:39501/*
mistachkindf562d52012-03-13 01:16:57502** This function is not available on Windows CE or WinRT.
503 */
504
505#if SQLITE_OS_WINCE || SQLITE_OS_WINRT
506# define osAreFileApisANSI() 1
507#endif
508
509/*
drh7acec682012-03-01 21:19:39510** Many system calls are accessed through pointer-to-functions so that
511** they may be overridden at runtime to facilitate fault injection during
512** testing and sandboxing. The following array holds the names and pointers
513** to all overrideable system calls.
514*/
mistachkin318507b2011-11-11 22:08:54515static struct win_syscall {
mistachkin48864df2013-03-21 21:20:32516 const char *zName; /* Name of the system call */
mistachkin318507b2011-11-11 22:08:54517 sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
518 sqlite3_syscall_ptr pDefault; /* Default value */
519} aSyscall[] = {
mistachkindf562d52012-03-13 01:16:57520#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
mistachkin318507b2011-11-11 22:08:54521 { "AreFileApisANSI", (SYSCALL)AreFileApisANSI, 0 },
mistachkin318507b2011-11-11 22:08:54522#else
523 { "AreFileApisANSI", (SYSCALL)0, 0 },
524#endif
525
mistachkin0df898e2012-03-14 20:17:34526#ifndef osAreFileApisANSI
mistachkindf562d52012-03-13 01:16:57527#define osAreFileApisANSI ((BOOL(WINAPI*)(VOID))aSyscall[0].pCurrent)
mistachkin0df898e2012-03-14 20:17:34528#endif
mistachkindf562d52012-03-13 01:16:57529
mistachkin318507b2011-11-11 22:08:54530#if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
531 { "CharLowerW", (SYSCALL)CharLowerW, 0 },
532#else
533 { "CharLowerW", (SYSCALL)0, 0 },
534#endif
535
536#define osCharLowerW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[1].pCurrent)
537
538#if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
539 { "CharUpperW", (SYSCALL)CharUpperW, 0 },
540#else
541 { "CharUpperW", (SYSCALL)0, 0 },
542#endif
543
544#define osCharUpperW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[2].pCurrent)
545
546 { "CloseHandle", (SYSCALL)CloseHandle, 0 },
547
548#define osCloseHandle ((BOOL(WINAPI*)(HANDLE))aSyscall[3].pCurrent)
549
550#if defined(SQLITE_WIN32_HAS_ANSI)
551 { "CreateFileA", (SYSCALL)CreateFileA, 0 },
552#else
553 { "CreateFileA", (SYSCALL)0, 0 },
554#endif
555
556#define osCreateFileA ((HANDLE(WINAPI*)(LPCSTR,DWORD,DWORD, \
557 LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[4].pCurrent)
558
mistachkindf562d52012-03-13 01:16:57559#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
mistachkin318507b2011-11-11 22:08:54560 { "CreateFileW", (SYSCALL)CreateFileW, 0 },
561#else
562 { "CreateFileW", (SYSCALL)0, 0 },
563#endif
564
565#define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \
566 LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent)
567
mistachkind5be6f02016-01-27 07:28:33568#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \
569 (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) && \
570 SQLITE_WIN32_CREATEFILEMAPPINGA
mistachkinc60941f2012-09-13 01:51:02571 { "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 },
572#else
573 { "CreateFileMappingA", (SYSCALL)0, 0 },
574#endif
575
576#define osCreateFileMappingA ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
577 DWORD,DWORD,DWORD,LPCSTR))aSyscall[6].pCurrent)
578
mistachkin1700b1c2012-08-14 01:45:12579#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
mistachkin73767822014-11-04 19:37:22580 (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
mistachkin318507b2011-11-11 22:08:54581 { "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 },
582#else
583 { "CreateFileMappingW", (SYSCALL)0, 0 },
584#endif
585
586#define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
mistachkinc60941f2012-09-13 01:51:02587 DWORD,DWORD,DWORD,LPCWSTR))aSyscall[7].pCurrent)
mistachkin318507b2011-11-11 22:08:54588
mistachkindf562d52012-03-13 01:16:57589#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
mistachkin318507b2011-11-11 22:08:54590 { "CreateMutexW", (SYSCALL)CreateMutexW, 0 },
591#else
592 { "CreateMutexW", (SYSCALL)0, 0 },
593#endif
594
595#define osCreateMutexW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,BOOL, \
mistachkinc60941f2012-09-13 01:51:02596 LPCWSTR))aSyscall[8].pCurrent)
mistachkin318507b2011-11-11 22:08:54597
598#if defined(SQLITE_WIN32_HAS_ANSI)
599 { "DeleteFileA", (SYSCALL)DeleteFileA, 0 },
600#else
601 { "DeleteFileA", (SYSCALL)0, 0 },
602#endif
603
mistachkinc60941f2012-09-13 01:51:02604#define osDeleteFileA ((BOOL(WINAPI*)(LPCSTR))aSyscall[9].pCurrent)
mistachkin318507b2011-11-11 22:08:54605
606#if defined(SQLITE_WIN32_HAS_WIDE)
607 { "DeleteFileW", (SYSCALL)DeleteFileW, 0 },
608#else
609 { "DeleteFileW", (SYSCALL)0, 0 },
610#endif
611
mistachkinc60941f2012-09-13 01:51:02612#define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[10].pCurrent)
mistachkin318507b2011-11-11 22:08:54613
614#if SQLITE_OS_WINCE
615 { "FileTimeToLocalFileTime", (SYSCALL)FileTimeToLocalFileTime, 0 },
616#else
617 { "FileTimeToLocalFileTime", (SYSCALL)0, 0 },
618#endif
619
stephan7b9407a2025-03-07 06:54:04620#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(const FILETIME*, \
mistachkinc60941f2012-09-13 01:51:02621 LPFILETIME))aSyscall[11].pCurrent)
mistachkin318507b2011-11-11 22:08:54622
623#if SQLITE_OS_WINCE
624 { "FileTimeToSystemTime", (SYSCALL)FileTimeToSystemTime, 0 },
625#else
626 { "FileTimeToSystemTime", (SYSCALL)0, 0 },
627#endif
628
stephan7b9407a2025-03-07 06:54:04629#define osFileTimeToSystemTime ((BOOL(WINAPI*)(const FILETIME*, \
mistachkinc60941f2012-09-13 01:51:02630 LPSYSTEMTIME))aSyscall[12].pCurrent)
mistachkin318507b2011-11-11 22:08:54631
632 { "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 },
633
mistachkinc60941f2012-09-13 01:51:02634#define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[13].pCurrent)
mistachkin318507b2011-11-11 22:08:54635
636#if defined(SQLITE_WIN32_HAS_ANSI)
637 { "FormatMessageA", (SYSCALL)FormatMessageA, 0 },
638#else
639 { "FormatMessageA", (SYSCALL)0, 0 },
640#endif
641
642#define osFormatMessageA ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPSTR, \
mistachkinc60941f2012-09-13 01:51:02643 DWORD,va_list*))aSyscall[14].pCurrent)
mistachkin318507b2011-11-11 22:08:54644
645#if defined(SQLITE_WIN32_HAS_WIDE)
646 { "FormatMessageW", (SYSCALL)FormatMessageW, 0 },
647#else
648 { "FormatMessageW", (SYSCALL)0, 0 },
649#endif
650
651#define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \
mistachkinc60941f2012-09-13 01:51:02652 DWORD,va_list*))aSyscall[15].pCurrent)
mistachkin318507b2011-11-11 22:08:54653
mistachkin08c1c312012-10-06 03:48:25654#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
mistachkin318507b2011-11-11 22:08:54655 { "FreeLibrary", (SYSCALL)FreeLibrary, 0 },
mistachkin08c1c312012-10-06 03:48:25656#else
657 { "FreeLibrary", (SYSCALL)0, 0 },
658#endif
mistachkin318507b2011-11-11 22:08:54659
mistachkinc60941f2012-09-13 01:51:02660#define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[16].pCurrent)
mistachkin318507b2011-11-11 22:08:54661
662 { "GetCurrentProcessId", (SYSCALL)GetCurrentProcessId, 0 },
663
mistachkinc60941f2012-09-13 01:51:02664#define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[17].pCurrent)
mistachkin318507b2011-11-11 22:08:54665
666#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI)
667 { "GetDiskFreeSpaceA", (SYSCALL)GetDiskFreeSpaceA, 0 },
668#else
669 { "GetDiskFreeSpaceA", (SYSCALL)0, 0 },
670#endif
671
672#define osGetDiskFreeSpaceA ((BOOL(WINAPI*)(LPCSTR,LPDWORD,LPDWORD,LPDWORD, \
mistachkinc60941f2012-09-13 01:51:02673 LPDWORD))aSyscall[18].pCurrent)
mistachkin318507b2011-11-11 22:08:54674
mistachkindf562d52012-03-13 01:16:57675#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
mistachkin318507b2011-11-11 22:08:54676 { "GetDiskFreeSpaceW", (SYSCALL)GetDiskFreeSpaceW, 0 },
677#else
678 { "GetDiskFreeSpaceW", (SYSCALL)0, 0 },
679#endif
680
681#define osGetDiskFreeSpaceW ((BOOL(WINAPI*)(LPCWSTR,LPDWORD,LPDWORD,LPDWORD, \
mistachkinc60941f2012-09-13 01:51:02682 LPDWORD))aSyscall[19].pCurrent)
mistachkin318507b2011-11-11 22:08:54683
684#if defined(SQLITE_WIN32_HAS_ANSI)
685 { "GetFileAttributesA", (SYSCALL)GetFileAttributesA, 0 },
686#else
687 { "GetFileAttributesA", (SYSCALL)0, 0 },
688#endif
689
mistachkinc60941f2012-09-13 01:51:02690#define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[20].pCurrent)
mistachkin318507b2011-11-11 22:08:54691
mistachkindf562d52012-03-13 01:16:57692#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
mistachkin318507b2011-11-11 22:08:54693 { "GetFileAttributesW", (SYSCALL)GetFileAttributesW, 0 },
694#else
695 { "GetFileAttributesW", (SYSCALL)0, 0 },
696#endif
697
mistachkinc60941f2012-09-13 01:51:02698#define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[21].pCurrent)
mistachkin318507b2011-11-11 22:08:54699
700#if defined(SQLITE_WIN32_HAS_WIDE)
701 { "GetFileAttributesExW", (SYSCALL)GetFileAttributesExW, 0 },
702#else
703 { "GetFileAttributesExW", (SYSCALL)0, 0 },
704#endif
705
706#define osGetFileAttributesExW ((BOOL(WINAPI*)(LPCWSTR,GET_FILEEX_INFO_LEVELS, \
mistachkinc60941f2012-09-13 01:51:02707 LPVOID))aSyscall[22].pCurrent)
mistachkin318507b2011-11-11 22:08:54708
mistachkindf562d52012-03-13 01:16:57709#if !SQLITE_OS_WINRT
mistachkin318507b2011-11-11 22:08:54710 { "GetFileSize", (SYSCALL)GetFileSize, 0 },
mistachkindf562d52012-03-13 01:16:57711#else
712 { "GetFileSize", (SYSCALL)0, 0 },
drh24560d12012-03-01 22:44:56713#endif
mistachkin318507b2011-11-11 22:08:54714
mistachkinc60941f2012-09-13 01:51:02715#define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[23].pCurrent)
mistachkin318507b2011-11-11 22:08:54716
717#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI)
718 { "GetFullPathNameA", (SYSCALL)GetFullPathNameA, 0 },
719#else
720 { "GetFullPathNameA", (SYSCALL)0, 0 },
721#endif
722
723#define osGetFullPathNameA ((DWORD(WINAPI*)(LPCSTR,DWORD,LPSTR, \
mistachkinc60941f2012-09-13 01:51:02724 LPSTR*))aSyscall[24].pCurrent)
mistachkin318507b2011-11-11 22:08:54725
mistachkinc5484652012-03-05 22:52:33726#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
mistachkin318507b2011-11-11 22:08:54727 { "GetFullPathNameW", (SYSCALL)GetFullPathNameW, 0 },
728#else
729 { "GetFullPathNameW", (SYSCALL)0, 0 },
730#endif
731
732#define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \
mistachkinc60941f2012-09-13 01:51:02733 LPWSTR*))aSyscall[25].pCurrent)
mistachkin318507b2011-11-11 22:08:54734
danb1ad83a2024-12-11 15:30:58735/*
736** For GetLastError(), MSDN says:
737**
738** Minimum supported client: Windows XP [desktop apps | UWP apps]
739** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps]
740*/
mistachkin318507b2011-11-11 22:08:54741 { "GetLastError", (SYSCALL)GetLastError, 0 },
742
mistachkinc60941f2012-09-13 01:51:02743#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent)
mistachkin318507b2011-11-11 22:08:54744
mistachkin08c1c312012-10-06 03:48:25745#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
mistachkin318507b2011-11-11 22:08:54746#if SQLITE_OS_WINCE
747 /* The GetProcAddressA() routine is only available on Windows CE. */
748 { "GetProcAddressA", (SYSCALL)GetProcAddressA, 0 },
749#else
750 /* All other Windows platforms expect GetProcAddress() to take
751 ** an ANSI string regardless of the _UNICODE setting */
752 { "GetProcAddressA", (SYSCALL)GetProcAddress, 0 },
753#endif
mistachkin08c1c312012-10-06 03:48:25754#else
755 { "GetProcAddressA", (SYSCALL)0, 0 },
756#endif
mistachkin318507b2011-11-11 22:08:54757
758#define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \
mistachkinc60941f2012-09-13 01:51:02759 LPCSTR))aSyscall[27].pCurrent)
mistachkin318507b2011-11-11 22:08:54760
mistachkindf562d52012-03-13 01:16:57761#if !SQLITE_OS_WINRT
mistachkin318507b2011-11-11 22:08:54762 { "GetSystemInfo", (SYSCALL)GetSystemInfo, 0 },
mistachkindf562d52012-03-13 01:16:57763#else
764 { "GetSystemInfo", (SYSCALL)0, 0 },
765#endif
mistachkin318507b2011-11-11 22:08:54766
mistachkinc60941f2012-09-13 01:51:02767#define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[28].pCurrent)
mistachkin318507b2011-11-11 22:08:54768
769 { "GetSystemTime", (SYSCALL)GetSystemTime, 0 },
770
mistachkinc60941f2012-09-13 01:51:02771#define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[29].pCurrent)
mistachkin318507b2011-11-11 22:08:54772
773#if !SQLITE_OS_WINCE
774 { "GetSystemTimeAsFileTime", (SYSCALL)GetSystemTimeAsFileTime, 0 },
775#else
776 { "GetSystemTimeAsFileTime", (SYSCALL)0, 0 },
777#endif
778
779#define osGetSystemTimeAsFileTime ((VOID(WINAPI*)( \
mistachkinc60941f2012-09-13 01:51:02780 LPFILETIME))aSyscall[30].pCurrent)
mistachkin318507b2011-11-11 22:08:54781
782#if defined(SQLITE_WIN32_HAS_ANSI)
783 { "GetTempPathA", (SYSCALL)GetTempPathA, 0 },
784#else
785 { "GetTempPathA", (SYSCALL)0, 0 },
786#endif
787
mistachkinc60941f2012-09-13 01:51:02788#define osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[31].pCurrent)
mistachkin318507b2011-11-11 22:08:54789
mistachkinc5484652012-03-05 22:52:33790#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
mistachkin318507b2011-11-11 22:08:54791 { "GetTempPathW", (SYSCALL)GetTempPathW, 0 },
792#else
793 { "GetTempPathW", (SYSCALL)0, 0 },
794#endif
795
mistachkinc60941f2012-09-13 01:51:02796#define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[32].pCurrent)
mistachkin318507b2011-11-11 22:08:54797
mistachkindf562d52012-03-13 01:16:57798#if !SQLITE_OS_WINRT
mistachkin318507b2011-11-11 22:08:54799 { "GetTickCount", (SYSCALL)GetTickCount, 0 },
mistachkindf562d52012-03-13 01:16:57800#else
801 { "GetTickCount", (SYSCALL)0, 0 },
802#endif
mistachkin318507b2011-11-11 22:08:54803
mistachkinc60941f2012-09-13 01:51:02804#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent)
mistachkin318507b2011-11-11 22:08:54805
mistachkind5be6f02016-01-27 07:28:33806#if defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_GETVERSIONEX
mistachkin318507b2011-11-11 22:08:54807 { "GetVersionExA", (SYSCALL)GetVersionExA, 0 },
808#else
809 { "GetVersionExA", (SYSCALL)0, 0 },
810#endif
811
812#define osGetVersionExA ((BOOL(WINAPI*)( \
mistachkinc60941f2012-09-13 01:51:02813 LPOSVERSIONINFOA))aSyscall[34].pCurrent)
mistachkin318507b2011-11-11 22:08:54814
mistachkin0f7e08e2013-11-27 03:01:34815#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
mistachkind5be6f02016-01-27 07:28:33816 SQLITE_WIN32_GETVERSIONEX
mistachkinb8af6a22013-09-13 23:27:39817 { "GetVersionExW", (SYSCALL)GetVersionExW, 0 },
818#else
819 { "GetVersionExW", (SYSCALL)0, 0 },
820#endif
821
822#define osGetVersionExW ((BOOL(WINAPI*)( \
823 LPOSVERSIONINFOW))aSyscall[35].pCurrent)
mistachkin318507b2011-11-11 22:08:54824
825 { "HeapAlloc", (SYSCALL)HeapAlloc, 0 },
826
827#define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \
mistachkinb8af6a22013-09-13 23:27:39828 SIZE_T))aSyscall[36].pCurrent)
mistachkin318507b2011-11-11 22:08:54829
mistachkindf562d52012-03-13 01:16:57830#if !SQLITE_OS_WINRT
mistachkin318507b2011-11-11 22:08:54831 { "HeapCreate", (SYSCALL)HeapCreate, 0 },
mistachkindf562d52012-03-13 01:16:57832#else
833 { "HeapCreate", (SYSCALL)0, 0 },
834#endif
mistachkin318507b2011-11-11 22:08:54835
836#define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \
mistachkinb8af6a22013-09-13 23:27:39837 SIZE_T))aSyscall[37].pCurrent)
mistachkin318507b2011-11-11 22:08:54838
mistachkindf562d52012-03-13 01:16:57839#if !SQLITE_OS_WINRT
mistachkin318507b2011-11-11 22:08:54840 { "HeapDestroy", (SYSCALL)HeapDestroy, 0 },
mistachkindf562d52012-03-13 01:16:57841#else
842 { "HeapDestroy", (SYSCALL)0, 0 },
843#endif
mistachkin318507b2011-11-11 22:08:54844
mistachkinb8af6a22013-09-13 23:27:39845#define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[38].pCurrent)
mistachkin318507b2011-11-11 22:08:54846
847 { "HeapFree", (SYSCALL)HeapFree, 0 },
848
mistachkinb8af6a22013-09-13 23:27:39849#define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[39].pCurrent)
mistachkin318507b2011-11-11 22:08:54850
851 { "HeapReAlloc", (SYSCALL)HeapReAlloc, 0 },
852
853#define osHeapReAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD,LPVOID, \
mistachkinb8af6a22013-09-13 23:27:39854 SIZE_T))aSyscall[40].pCurrent)
mistachkin318507b2011-11-11 22:08:54855
856 { "HeapSize", (SYSCALL)HeapSize, 0 },
857
858#define osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \
mistachkinb8af6a22013-09-13 23:27:39859 LPCVOID))aSyscall[41].pCurrent)
mistachkin318507b2011-11-11 22:08:54860
mistachkindf562d52012-03-13 01:16:57861#if !SQLITE_OS_WINRT
mistachkin318507b2011-11-11 22:08:54862 { "HeapValidate", (SYSCALL)HeapValidate, 0 },
mistachkindf562d52012-03-13 01:16:57863#else
864 { "HeapValidate", (SYSCALL)0, 0 },
865#endif
mistachkin318507b2011-11-11 22:08:54866
867#define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \
mistachkinb8af6a22013-09-13 23:27:39868 LPCVOID))aSyscall[42].pCurrent)
mistachkin318507b2011-11-11 22:08:54869
mistachkin5134a812013-11-08 19:51:12870#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
mistachkine8f91052013-11-08 18:13:48871 { "HeapCompact", (SYSCALL)HeapCompact, 0 },
872#else
873 { "HeapCompact", (SYSCALL)0, 0 },
874#endif
875
876#define osHeapCompact ((UINT(WINAPI*)(HANDLE,DWORD))aSyscall[43].pCurrent)
877
mistachkin08c1c312012-10-06 03:48:25878#if defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
mistachkin318507b2011-11-11 22:08:54879 { "LoadLibraryA", (SYSCALL)LoadLibraryA, 0 },
880#else
881 { "LoadLibraryA", (SYSCALL)0, 0 },
882#endif
883
mistachkine8f91052013-11-08 18:13:48884#define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[44].pCurrent)
mistachkin318507b2011-11-11 22:08:54885
mistachkin08c1c312012-10-06 03:48:25886#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
887 !defined(SQLITE_OMIT_LOAD_EXTENSION)
mistachkin318507b2011-11-11 22:08:54888 { "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 },
889#else
890 { "LoadLibraryW", (SYSCALL)0, 0 },
891#endif
892
mistachkine8f91052013-11-08 18:13:48893#define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[45].pCurrent)
mistachkin318507b2011-11-11 22:08:54894
mistachkindf562d52012-03-13 01:16:57895#if !SQLITE_OS_WINRT
mistachkin318507b2011-11-11 22:08:54896 { "LocalFree", (SYSCALL)LocalFree, 0 },
mistachkindf562d52012-03-13 01:16:57897#else
898 { "LocalFree", (SYSCALL)0, 0 },
899#endif
mistachkin318507b2011-11-11 22:08:54900
mistachkine8f91052013-11-08 18:13:48901#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[46].pCurrent)
mistachkin318507b2011-11-11 22:08:54902
mistachkindf562d52012-03-13 01:16:57903#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
mistachkin318507b2011-11-11 22:08:54904 { "LockFile", (SYSCALL)LockFile, 0 },
mistachkin318507b2011-11-11 22:08:54905#else
906 { "LockFile", (SYSCALL)0, 0 },
907#endif
908
stephan42e5ceb2025-03-10 15:15:13909#if !defined(osLockFile) && defined(SQLITE_WIN32_HAS_ANSI)
mistachkindf562d52012-03-13 01:16:57910#define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
mistachkine8f91052013-11-08 18:13:48911 DWORD))aSyscall[47].pCurrent)
mistachkin0df898e2012-03-14 20:17:34912#endif
mistachkindf562d52012-03-13 01:16:57913
mistachkin318507b2011-11-11 22:08:54914#if !SQLITE_OS_WINCE
915 { "LockFileEx", (SYSCALL)LockFileEx, 0 },
mistachkin318507b2011-11-11 22:08:54916#else
917 { "LockFileEx", (SYSCALL)0, 0 },
918#endif
919
mistachkin0df898e2012-03-14 20:17:34920#ifndef osLockFileEx
mistachkin5cfbeac2012-03-13 01:30:20921#define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \
mistachkine8f91052013-11-08 18:13:48922 LPOVERLAPPED))aSyscall[48].pCurrent)
mistachkin0df898e2012-03-14 20:17:34923#endif
mistachkin5cfbeac2012-03-13 01:30:20924
mistachkin73767822014-11-04 19:37:22925#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && \
926 (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
mistachkin318507b2011-11-11 22:08:54927 { "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 },
mistachkindf562d52012-03-13 01:16:57928#else
929 { "MapViewOfFile", (SYSCALL)0, 0 },
930#endif
mistachkin318507b2011-11-11 22:08:54931
932#define osMapViewOfFile ((LPVOID(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
mistachkine8f91052013-11-08 18:13:48933 SIZE_T))aSyscall[49].pCurrent)
mistachkin318507b2011-11-11 22:08:54934
935 { "MultiByteToWideChar", (SYSCALL)MultiByteToWideChar, 0 },
936
937#define osMultiByteToWideChar ((int(WINAPI*)(UINT,DWORD,LPCSTR,int,LPWSTR, \
mistachkine8f91052013-11-08 18:13:48938 int))aSyscall[50].pCurrent)
mistachkin318507b2011-11-11 22:08:54939
940 { "QueryPerformanceCounter", (SYSCALL)QueryPerformanceCounter, 0 },
941
942#define osQueryPerformanceCounter ((BOOL(WINAPI*)( \
mistachkine8f91052013-11-08 18:13:48943 LARGE_INTEGER*))aSyscall[51].pCurrent)
mistachkin318507b2011-11-11 22:08:54944
945 { "ReadFile", (SYSCALL)ReadFile, 0 },
946
947#define osReadFile ((BOOL(WINAPI*)(HANDLE,LPVOID,DWORD,LPDWORD, \
mistachkine8f91052013-11-08 18:13:48948 LPOVERLAPPED))aSyscall[52].pCurrent)
mistachkin318507b2011-11-11 22:08:54949
950 { "SetEndOfFile", (SYSCALL)SetEndOfFile, 0 },
951
mistachkine8f91052013-11-08 18:13:48952#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[53].pCurrent)
mistachkin318507b2011-11-11 22:08:54953
mistachkindf562d52012-03-13 01:16:57954#if !SQLITE_OS_WINRT
mistachkin318507b2011-11-11 22:08:54955 { "SetFilePointer", (SYSCALL)SetFilePointer, 0 },
mistachkindf562d52012-03-13 01:16:57956#else
957 { "SetFilePointer", (SYSCALL)0, 0 },
drh8045df02012-03-01 22:06:30958#endif
mistachkin318507b2011-11-11 22:08:54959
960#define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \
mistachkine8f91052013-11-08 18:13:48961 DWORD))aSyscall[54].pCurrent)
mistachkin318507b2011-11-11 22:08:54962
mistachkindf562d52012-03-13 01:16:57963#if !SQLITE_OS_WINRT
mistachkin318507b2011-11-11 22:08:54964 { "Sleep", (SYSCALL)Sleep, 0 },
mistachkindf562d52012-03-13 01:16:57965#else
966 { "Sleep", (SYSCALL)0, 0 },
drh7acec682012-03-01 21:19:39967#endif
mistachkin318507b2011-11-11 22:08:54968
mistachkine8f91052013-11-08 18:13:48969#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[55].pCurrent)
mistachkin318507b2011-11-11 22:08:54970
971 { "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 },
972
stephan7b9407a2025-03-07 06:54:04973#define osSystemTimeToFileTime ((BOOL(WINAPI*)(const SYSTEMTIME*, \
mistachkine8f91052013-11-08 18:13:48974 LPFILETIME))aSyscall[56].pCurrent)
mistachkin318507b2011-11-11 22:08:54975
mistachkindf562d52012-03-13 01:16:57976#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
mistachkin318507b2011-11-11 22:08:54977 { "UnlockFile", (SYSCALL)UnlockFile, 0 },
mistachkin318507b2011-11-11 22:08:54978#else
979 { "UnlockFile", (SYSCALL)0, 0 },
980#endif
981
stephan42e5ceb2025-03-10 15:15:13982#if !defined(osUnlockFile) && defined(SQLITE_WIN32_HAS_ANSI)
mistachkindf562d52012-03-13 01:16:57983#define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
mistachkine8f91052013-11-08 18:13:48984 DWORD))aSyscall[57].pCurrent)
mistachkin0df898e2012-03-14 20:17:34985#endif
mistachkindf562d52012-03-13 01:16:57986
mistachkin318507b2011-11-11 22:08:54987#if !SQLITE_OS_WINCE
988 { "UnlockFileEx", (SYSCALL)UnlockFileEx, 0 },
mistachkin318507b2011-11-11 22:08:54989#else
990 { "UnlockFileEx", (SYSCALL)0, 0 },
991#endif
992
mistachkindf562d52012-03-13 01:16:57993#define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
mistachkine8f91052013-11-08 18:13:48994 LPOVERLAPPED))aSyscall[58].pCurrent)
mistachkindf562d52012-03-13 01:16:57995
mistachkin73767822014-11-04 19:37:22996#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
mistachkin318507b2011-11-11 22:08:54997 { "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 },
mistachkin1700b1c2012-08-14 01:45:12998#else
999 { "UnmapViewOfFile", (SYSCALL)0, 0 },
1000#endif
mistachkin318507b2011-11-11 22:08:541001
mistachkine8f91052013-11-08 18:13:481002#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[59].pCurrent)
mistachkin318507b2011-11-11 22:08:541003
1004 { "WideCharToMultiByte", (SYSCALL)WideCharToMultiByte, 0 },
1005
1006#define osWideCharToMultiByte ((int(WINAPI*)(UINT,DWORD,LPCWSTR,int,LPSTR,int, \
mistachkine8f91052013-11-08 18:13:481007 LPCSTR,LPBOOL))aSyscall[60].pCurrent)
mistachkin318507b2011-11-11 22:08:541008
1009 { "WriteFile", (SYSCALL)WriteFile, 0 },
1010
1011#define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \
mistachkine8f91052013-11-08 18:13:481012 LPOVERLAPPED))aSyscall[61].pCurrent)
mistachkin318507b2011-11-11 22:08:541013
mistachkin401e9152012-06-04 05:18:321014#if SQLITE_OS_WINRT
mistachkindf562d52012-03-13 01:16:571015 { "CreateEventExW", (SYSCALL)CreateEventExW, 0 },
mistachkin75b70a22012-03-02 13:47:161016#else
mistachkindf562d52012-03-13 01:16:571017 { "CreateEventExW", (SYSCALL)0, 0 },
mistachkin75b70a22012-03-02 13:47:161018#endif
1019
mistachkindf562d52012-03-13 01:16:571020#define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \
mistachkine8f91052013-11-08 18:13:481021 DWORD,DWORD))aSyscall[62].pCurrent)
mistachkindf562d52012-03-13 01:16:571022
danb1ad83a2024-12-11 15:30:581023/*
1024** For WaitForSingleObject(), MSDN says:
1025**
1026** Minimum supported client: Windows XP [desktop apps | UWP apps]
1027** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps]
1028*/
mistachkin75b70a22012-03-02 13:47:161029 { "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 },
mistachkin75b70a22012-03-02 13:47:161030
1031#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \
mistachkine8f91052013-11-08 18:13:481032 DWORD))aSyscall[63].pCurrent)
mistachkin75b70a22012-03-02 13:47:161033
mistachkin92c2e0d2014-10-16 18:34:501034#if !SQLITE_OS_WINCE
mistachkin75b70a22012-03-02 13:47:161035 { "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 },
mistachkin92c2e0d2014-10-16 18:34:501036#else
1037 { "WaitForSingleObjectEx", (SYSCALL)0, 0 },
1038#endif
mistachkin75b70a22012-03-02 13:47:161039
mistachkin5cfbeac2012-03-13 01:30:201040#define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \
mistachkine8f91052013-11-08 18:13:481041 BOOL))aSyscall[64].pCurrent)
mistachkin5cfbeac2012-03-13 01:30:201042
mistachkina0aa13b2012-08-13 22:05:221043#if SQLITE_OS_WINRT
mistachkin75b70a22012-03-02 13:47:161044 { "SetFilePointerEx", (SYSCALL)SetFilePointerEx, 0 },
mistachkin75b70a22012-03-02 13:47:161045#else
1046 { "SetFilePointerEx", (SYSCALL)0, 0 },
1047#endif
1048
mistachkin5cfbeac2012-03-13 01:30:201049#define osSetFilePointerEx ((BOOL(WINAPI*)(HANDLE,LARGE_INTEGER, \
mistachkine8f91052013-11-08 18:13:481050 PLARGE_INTEGER,DWORD))aSyscall[65].pCurrent)
mistachkin5cfbeac2012-03-13 01:30:201051
mistachkin401e9152012-06-04 05:18:321052#if SQLITE_OS_WINRT
mistachkin75b70a22012-03-02 13:47:161053 { "GetFileInformationByHandleEx", (SYSCALL)GetFileInformationByHandleEx, 0 },
mistachkin75b70a22012-03-02 13:47:161054#else
1055 { "GetFileInformationByHandleEx", (SYSCALL)0, 0 },
1056#endif
1057
mistachkin5cfbeac2012-03-13 01:30:201058#define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \
mistachkine8f91052013-11-08 18:13:481059 FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[66].pCurrent)
mistachkin5cfbeac2012-03-13 01:30:201060
mistachkin73767822014-11-04 19:37:221061#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
mistachkin1e6eea92012-05-31 22:12:261062 { "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 },
mistachkina7494862012-04-18 05:57:381063#else
mistachkin1e6eea92012-05-31 22:12:261064 { "MapViewOfFileFromApp", (SYSCALL)0, 0 },
mistachkina7494862012-04-18 05:57:381065#endif
mistachkin287a48d2012-03-03 13:15:251066
mistachkin1e6eea92012-05-31 22:12:261067#define osMapViewOfFileFromApp ((LPVOID(WINAPI*)(HANDLE,ULONG,ULONG64, \
mistachkine8f91052013-11-08 18:13:481068 SIZE_T))aSyscall[67].pCurrent)
mistachkin287a48d2012-03-03 13:15:251069
mistachkindf562d52012-03-13 01:16:571070#if SQLITE_OS_WINRT
1071 { "CreateFile2", (SYSCALL)CreateFile2, 0 },
mistachkin5483f772012-03-07 20:11:471072#else
mistachkindf562d52012-03-13 01:16:571073 { "CreateFile2", (SYSCALL)0, 0 },
mistachkin5483f772012-03-07 20:11:471074#endif
1075
1076#define osCreateFile2 ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD,DWORD, \
mistachkine8f91052013-11-08 18:13:481077 LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[68].pCurrent)
mistachkin5483f772012-03-07 20:11:471078
mistachkin08c1c312012-10-06 03:48:251079#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_LOAD_EXTENSION)
mistachkindf562d52012-03-13 01:16:571080 { "LoadPackagedLibrary", (SYSCALL)LoadPackagedLibrary, 0 },
mistachkin5483f772012-03-07 20:11:471081#else
mistachkindf562d52012-03-13 01:16:571082 { "LoadPackagedLibrary", (SYSCALL)0, 0 },
mistachkin5483f772012-03-07 20:11:471083#endif
1084
1085#define osLoadPackagedLibrary ((HMODULE(WINAPI*)(LPCWSTR, \
mistachkine8f91052013-11-08 18:13:481086 DWORD))aSyscall[69].pCurrent)
mistachkin5483f772012-03-07 20:11:471087
mistachkindf562d52012-03-13 01:16:571088#if SQLITE_OS_WINRT
1089 { "GetTickCount64", (SYSCALL)GetTickCount64, 0 },
1090#else
1091 { "GetTickCount64", (SYSCALL)0, 0 },
1092#endif
1093
mistachkine8f91052013-11-08 18:13:481094#define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[70].pCurrent)
mistachkindf562d52012-03-13 01:16:571095
1096#if SQLITE_OS_WINRT
1097 { "GetNativeSystemInfo", (SYSCALL)GetNativeSystemInfo, 0 },
1098#else
1099 { "GetNativeSystemInfo", (SYSCALL)0, 0 },
1100#endif
1101
1102#define osGetNativeSystemInfo ((VOID(WINAPI*)( \
mistachkine8f91052013-11-08 18:13:481103 LPSYSTEM_INFO))aSyscall[71].pCurrent)
mistachkindf562d52012-03-13 01:16:571104
mistachkinf4f327c2012-03-13 03:35:071105#if defined(SQLITE_WIN32_HAS_ANSI)
1106 { "OutputDebugStringA", (SYSCALL)OutputDebugStringA, 0 },
1107#else
1108 { "OutputDebugStringA", (SYSCALL)0, 0 },
1109#endif
1110
mistachkine8f91052013-11-08 18:13:481111#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[72].pCurrent)
mistachkinf4f327c2012-03-13 03:35:071112
1113#if defined(SQLITE_WIN32_HAS_WIDE)
1114 { "OutputDebugStringW", (SYSCALL)OutputDebugStringW, 0 },
1115#else
1116 { "OutputDebugStringW", (SYSCALL)0, 0 },
1117#endif
1118
mistachkine8f91052013-11-08 18:13:481119#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[73].pCurrent)
mistachkinf4f327c2012-03-13 03:35:071120
mistachkin0df898e2012-03-14 20:17:341121 { "GetProcessHeap", (SYSCALL)GetProcessHeap, 0 },
1122
mistachkine8f91052013-11-08 18:13:481123#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[74].pCurrent)
mistachkin0df898e2012-03-14 20:17:341124
mistachkin73767822014-11-04 19:37:221125#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
mistachkin1e6eea92012-05-31 22:12:261126 { "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 },
1127#else
1128 { "CreateFileMappingFromApp", (SYSCALL)0, 0 },
1129#endif
1130
1131#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \
mistachkine8f91052013-11-08 18:13:481132 LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent)
mistachkin1e6eea92012-05-31 22:12:261133
mistachkin17835a52014-08-06 03:06:011134/*
1135** NOTE: On some sub-platforms, the InterlockedCompareExchange "function"
1136** is really just a macro that uses a compiler intrinsic (e.g. x64).
drh2abe6a22014-08-06 11:57:541137** So do not try to make this is into a redefinable interface.
mistachkin17835a52014-08-06 03:06:011138*/
mistachkin91d12492014-08-11 17:38:381139#if defined(InterlockedCompareExchange)
1140 { "InterlockedCompareExchange", (SYSCALL)0, 0 },
1141
mistachkin17835a52014-08-06 03:06:011142#define osInterlockedCompareExchange InterlockedCompareExchange
mistachkin91d12492014-08-11 17:38:381143#else
mistachkin202cb642014-07-31 18:54:011144 { "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 },
1145
mistachkince64d612014-08-14 18:31:561146#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG \
1147 SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[76].pCurrent)
mistachkin91d12492014-08-11 17:38:381148#endif /* defined(InterlockedCompareExchange) */
mistachkin202cb642014-07-31 18:54:011149
mistachkine45e0fb2015-01-21 00:48:461150#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
1151 { "UuidCreate", (SYSCALL)UuidCreate, 0 },
1152#else
1153 { "UuidCreate", (SYSCALL)0, 0 },
1154#endif
1155
1156#define osUuidCreate ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[77].pCurrent)
1157
1158#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
1159 { "UuidCreateSequential", (SYSCALL)UuidCreateSequential, 0 },
1160#else
1161 { "UuidCreateSequential", (SYSCALL)0, 0 },
1162#endif
1163
1164#define osUuidCreateSequential \
1165 ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[78].pCurrent)
1166
mistachkinccb43712015-03-26 23:36:351167#if !defined(SQLITE_NO_SYNC) && SQLITE_MAX_MMAP_SIZE>0
1168 { "FlushViewOfFile", (SYSCALL)FlushViewOfFile, 0 },
1169#else
1170 { "FlushViewOfFile", (SYSCALL)0, 0 },
1171#endif
1172
1173#define osFlushViewOfFile \
1174 ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent)
1175
danb1ad83a2024-12-11 15:30:581176/*
1177** If SQLITE_ENABLE_SETLK_TIMEOUT is defined, we require CreateEvent()
1178** to implement blocking locks with timeouts. MSDN says:
1179**
1180** Minimum supported client: Windows XP [desktop apps | UWP apps]
1181** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps]
1182*/
1183#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
1184 { "CreateEvent", (SYSCALL)CreateEvent, 0 },
1185#else
1186 { "CreateEvent", (SYSCALL)0, 0 },
1187#endif
1188
1189#define osCreateEvent ( \
1190 (HANDLE(WINAPI*) (LPSECURITY_ATTRIBUTES,BOOL,BOOL,LPCSTR)) \
1191 aSyscall[80].pCurrent \
1192)
1193
dance502822024-12-24 14:44:381194/*
1195** If SQLITE_ENABLE_SETLK_TIMEOUT is defined, we require CancelIo()
1196** for the case where a timeout expires and a lock request must be
1197** cancelled.
1198**
1199** Minimum supported client: Windows XP [desktop apps | UWP apps]
1200** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps]
1201*/
1202#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
1203 { "CancelIo", (SYSCALL)CancelIo, 0 },
1204#else
1205 { "CancelIo", (SYSCALL)0, 0 },
1206#endif
1207
1208#define osCancelIo ((BOOL(WINAPI*)(HANDLE))aSyscall[81].pCurrent)
1209
stephan7b9407a2025-03-07 06:54:041210#if defined(SQLITE_WIN32_HAS_WIDE) && defined(_WIN32)
1211 { "GetModuleHandleW", (SYSCALL)GetModuleHandleW, 0 },
1212#else
1213 { "GetModuleHandleW", (SYSCALL)0, 0 },
1214#endif
1215
1216#define osGetModuleHandleW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[82].pCurrent)
1217
1218#ifndef _WIN32
1219 { "getenv", (SYSCALL)getenv, 0 },
1220#else
1221 { "getenv", (SYSCALL)0, 0 },
1222#endif
1223
1224#define osGetenv ((const char *(*)(const char *))aSyscall[83].pCurrent)
1225
1226#ifndef _WIN32
1227 { "getcwd", (SYSCALL)getcwd, 0 },
1228#else
1229 { "getcwd", (SYSCALL)0, 0 },
1230#endif
1231
1232#define osGetcwd ((char*(*)(char*,size_t))aSyscall[84].pCurrent)
1233
1234#ifndef _WIN32
1235 { "readlink", (SYSCALL)readlink, 0 },
1236#else
1237 { "readlink", (SYSCALL)0, 0 },
1238#endif
1239
1240#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[85].pCurrent)
1241
1242#ifndef _WIN32
1243 { "lstat", (SYSCALL)lstat, 0 },
1244#else
1245 { "lstat", (SYSCALL)0, 0 },
1246#endif
1247
1248#define osLstat ((int(*)(const char*,struct stat*))aSyscall[86].pCurrent)
1249
1250#ifndef _WIN32
1251 { "__errno", (SYSCALL)__errno, 0 },
1252#else
1253 { "__errno", (SYSCALL)0, 0 },
1254#endif
1255
1256#define osErrno (*((int*(*)(void))aSyscall[87].pCurrent)())
1257
1258#ifndef _WIN32
1259 { "cygwin_conv_path", (SYSCALL)cygwin_conv_path, 0 },
1260#else
1261 { "cygwin_conv_path", (SYSCALL)0, 0 },
1262#endif
1263
1264#define osCygwin_conv_path ((size_t(*)(unsigned int, \
1265 const void *, void *, size_t))aSyscall[88].pCurrent)
1266
mistachkin318507b2011-11-11 22:08:541267}; /* End of the overrideable system calls */
1268
1269/*
1270** This is the xSetSystemCall() method of sqlite3_vfs for all of the
larrybrbc917382023-06-07 08:40:311271** "win32" VFSes. Return SQLITE_OK upon successfully updating the
mistachkin318507b2011-11-11 22:08:541272** system call pointer, or SQLITE_NOTFOUND if there is no configurable
1273** system call named zName.
1274*/
1275static int winSetSystemCall(
1276 sqlite3_vfs *pNotUsed, /* The VFS pointer. Not used */
1277 const char *zName, /* Name of system call to override */
1278 sqlite3_syscall_ptr pNewFunc /* Pointer to new system call value */
1279){
1280 unsigned int i;
1281 int rc = SQLITE_NOTFOUND;
1282
1283 UNUSED_PARAMETER(pNotUsed);
1284 if( zName==0 ){
1285 /* If no zName is given, restore all system calls to their default
1286 ** settings and return NULL
1287 */
1288 rc = SQLITE_OK;
1289 for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
1290 if( aSyscall[i].pDefault ){
1291 aSyscall[i].pCurrent = aSyscall[i].pDefault;
1292 }
1293 }
1294 }else{
1295 /* If zName is specified, operate on only the one system call
1296 ** specified.
1297 */
1298 for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
1299 if( strcmp(zName, aSyscall[i].zName)==0 ){
1300 if( aSyscall[i].pDefault==0 ){
1301 aSyscall[i].pDefault = aSyscall[i].pCurrent;
1302 }
1303 rc = SQLITE_OK;
1304 if( pNewFunc==0 ) pNewFunc = aSyscall[i].pDefault;
1305 aSyscall[i].pCurrent = pNewFunc;
1306 break;
1307 }
1308 }
1309 }
1310 return rc;
1311}
1312
1313/*
1314** Return the value of a system call. Return NULL if zName is not a
1315** recognized system call name. NULL is also returned if the system call
1316** is currently undefined.
1317*/
1318static sqlite3_syscall_ptr winGetSystemCall(
1319 sqlite3_vfs *pNotUsed,
1320 const char *zName
1321){
1322 unsigned int i;
1323
1324 UNUSED_PARAMETER(pNotUsed);
1325 for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
1326 if( strcmp(zName, aSyscall[i].zName)==0 ) return aSyscall[i].pCurrent;
1327 }
1328 return 0;
1329}
1330
1331/*
1332** Return the name of the first system call after zName. If zName==NULL
1333** then return the name of the first system call. Return NULL if zName
1334** is the last system call or if zName is not the name of a valid
1335** system call.
1336*/
1337static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){
1338 int i = -1;
1339
1340 UNUSED_PARAMETER(p);
1341 if( zName ){
1342 for(i=0; i<ArraySize(aSyscall)-1; i++){
1343 if( strcmp(zName, aSyscall[i].zName)==0 ) break;
1344 }
1345 }
1346 for(i++; i<ArraySize(aSyscall); i++){
1347 if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
1348 }
1349 return 0;
1350}
1351
mistachkin7f9d1792013-11-08 20:10:571352#ifdef SQLITE_WIN32_MALLOC
mistachkin318507b2011-11-11 22:08:541353/*
mistachkine8f91052013-11-08 18:13:481354** If a Win32 native heap has been configured, this function will attempt to
1355** compact it. Upon success, SQLITE_OK will be returned. Upon failure, one
1356** of SQLITE_NOMEM, SQLITE_ERROR, or SQLITE_NOTFOUND will be returned. The
1357** "pnLargest" argument, if non-zero, will be used to return the size of the
1358** largest committed free block in the heap, in bytes.
1359*/
1360int sqlite3_win32_compact_heap(LPUINT pnLargest){
1361 int rc = SQLITE_OK;
1362 UINT nLargest = 0;
1363 HANDLE hHeap;
1364
1365 winMemAssertMagic();
1366 hHeap = winMemGetHeap();
1367 assert( hHeap!=0 );
1368 assert( hHeap!=INVALID_HANDLE_VALUE );
1369#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
1370 assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
1371#endif
mistachkin5134a812013-11-08 19:51:121372#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
mistachkine8f91052013-11-08 18:13:481373 if( (nLargest=osHeapCompact(hHeap, SQLITE_WIN32_HEAP_FLAGS))==0 ){
1374 DWORD lastErrno = osGetLastError();
1375 if( lastErrno==NO_ERROR ){
1376 sqlite3_log(SQLITE_NOMEM, "failed to HeapCompact (no space), heap=%p",
1377 (void*)hHeap);
mistachkinfad30392016-02-13 23:43:461378 rc = SQLITE_NOMEM_BKPT;
mistachkine8f91052013-11-08 18:13:481379 }else{
mistachkin17bc3ff2013-11-08 18:37:021380 sqlite3_log(SQLITE_ERROR, "failed to HeapCompact (%lu), heap=%p",
mistachkine8f91052013-11-08 18:13:481381 osGetLastError(), (void*)hHeap);
1382 rc = SQLITE_ERROR;
1383 }
1384 }
1385#else
mistachkin17bc3ff2013-11-08 18:37:021386 sqlite3_log(SQLITE_NOTFOUND, "failed to HeapCompact, heap=%p",
1387 (void*)hHeap);
mistachkine8f91052013-11-08 18:13:481388 rc = SQLITE_NOTFOUND;
1389#endif
1390 if( pnLargest ) *pnLargest = nLargest;
1391 return rc;
1392}
1393
1394/*
1395** If a Win32 native heap has been configured, this function will attempt to
1396** destroy and recreate it. If the Win32 native heap is not isolated and/or
1397** the sqlite3_memory_used() function does not return zero, SQLITE_BUSY will
1398** be returned and no changes will be made to the Win32 native heap.
1399*/
1400int sqlite3_win32_reset_heap(){
1401 int rc;
drh067b92b2020-06-19 15:24:121402 MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) /* The main static mutex */
mistachkine8f91052013-11-08 18:13:481403 MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */
drh067b92b2020-06-19 15:24:121404 MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
drh97a7e5e2016-04-26 18:58:541405 MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); )
drh067b92b2020-06-19 15:24:121406 sqlite3_mutex_enter(pMainMtx);
mistachkine8f91052013-11-08 18:13:481407 sqlite3_mutex_enter(pMem);
mistachkin7f9d1792013-11-08 20:10:571408 winMemAssertMagic();
1409 if( winMemGetHeap()!=NULL && winMemGetOwned() && sqlite3_memory_used()==0 ){
mistachkine8f91052013-11-08 18:13:481410 /*
1411 ** At this point, there should be no outstanding memory allocations on
drh067b92b2020-06-19 15:24:121412 ** the heap. Also, since both the main and memsys locks are currently
mistachkine8f91052013-11-08 18:13:481413 ** being held by us, no other function (i.e. from another thread) should
1414 ** be able to even access the heap. Attempt to destroy and recreate our
1415 ** isolated Win32 native heap now.
1416 */
mistachkin7f9d1792013-11-08 20:10:571417 assert( winMemGetHeap()!=NULL );
1418 assert( winMemGetOwned() );
1419 assert( sqlite3_memory_used()==0 );
mistachkine8f91052013-11-08 18:13:481420 winMemShutdown(winMemGetDataPtr());
mistachkin7f9d1792013-11-08 20:10:571421 assert( winMemGetHeap()==NULL );
1422 assert( !winMemGetOwned() );
1423 assert( sqlite3_memory_used()==0 );
mistachkin2eb09662013-11-08 18:52:451424 rc = winMemInit(winMemGetDataPtr());
mistachkin7f9d1792013-11-08 20:10:571425 assert( rc!=SQLITE_OK || winMemGetHeap()!=NULL );
1426 assert( rc!=SQLITE_OK || winMemGetOwned() );
1427 assert( rc!=SQLITE_OK || sqlite3_memory_used()==0 );
mistachkine8f91052013-11-08 18:13:481428 }else{
1429 /*
1430 ** The Win32 native heap cannot be modified because it may be in use.
1431 */
1432 rc = SQLITE_BUSY;
1433 }
1434 sqlite3_mutex_leave(pMem);
drh067b92b2020-06-19 15:24:121435 sqlite3_mutex_leave(pMainMtx);
mistachkine8f91052013-11-08 18:13:481436 return rc;
1437}
mistachkin7f9d1792013-11-08 20:10:571438#endif /* SQLITE_WIN32_MALLOC */
mistachkine8f91052013-11-08 18:13:481439
stephan7b9407a2025-03-07 06:54:041440#ifdef _WIN32
drhc0929982005-09-05 19:08:291441/*
mistachkinf4f327c2012-03-13 03:35:071442** This function outputs the specified (ANSI) string to the Win32 debugger
1443** (if available).
1444*/
1445
mistachkin7e87eae2013-02-12 09:46:481446void sqlite3_win32_write_debug(const char *zBuf, int nBuf){
mistachkinf4f327c2012-03-13 03:35:071447 char zDbgBuf[SQLITE_WIN32_DBG_BUF_SIZE];
mistachkin16afb9e2012-03-14 23:08:591448 int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /* may be negative. */
mistachkinf4f327c2012-03-13 03:35:071449 if( nMin<-1 ) nMin = -1; /* all negative values become -1. */
mistachkin5ff72402012-03-13 03:38:221450 assert( nMin==-1 || nMin==0 || nMin<SQLITE_WIN32_DBG_BUF_SIZE );
mistachkin12931202016-04-04 02:05:461451#ifdef SQLITE_ENABLE_API_ARMOR
1452 if( !zBuf ){
1453 (void)SQLITE_MISUSE_BKPT;
1454 return;
1455 }
1456#endif
mistachkinf4f327c2012-03-13 03:35:071457#if defined(SQLITE_WIN32_HAS_ANSI)
1458 if( nMin>0 ){
1459 memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE);
1460 memcpy(zDbgBuf, zBuf, nMin);
mistachkinca04d8a2012-03-19 23:28:351461 osOutputDebugStringA(zDbgBuf);
mistachkinf4f327c2012-03-13 03:35:071462 }else{
mistachkinca04d8a2012-03-19 23:28:351463 osOutputDebugStringA(zBuf);
mistachkinf4f327c2012-03-13 03:35:071464 }
1465#elif defined(SQLITE_WIN32_HAS_WIDE)
1466 memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE);
1467 if ( osMultiByteToWideChar(
1468 osAreFileApisANSI() ? CP_ACP : CP_OEMCP, 0, zBuf,
mistachkin0df898e2012-03-14 20:17:341469 nMin, (LPWSTR)zDbgBuf, SQLITE_WIN32_DBG_BUF_SIZE/sizeof(WCHAR))<=0 ){
mistachkinf4f327c2012-03-13 03:35:071470 return;
1471 }
mistachkin0df898e2012-03-14 20:17:341472 osOutputDebugStringW((LPCWSTR)zDbgBuf);
mistachkinf4f327c2012-03-13 03:35:071473#else
1474 if( nMin>0 ){
1475 memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE);
1476 memcpy(zDbgBuf, zBuf, nMin);
1477 fprintf(stderr, "%s", zDbgBuf);
1478 }else{
1479 fprintf(stderr, "%s", zBuf);
1480 }
1481#endif
1482}
stephan7b9407a2025-03-07 06:54:041483#endif /* _WIN32 */
mistachkinf4f327c2012-03-13 03:35:071484
1485/*
1486** The following routine suspends the current thread for at least ms
1487** milliseconds. This is equivalent to the Win32 Sleep() interface.
drh7acec682012-03-01 21:19:391488*/
1489#if SQLITE_OS_WINRT
mistachkinf4f327c2012-03-13 03:35:071490static HANDLE sleepObj = NULL;
drh7acec682012-03-01 21:19:391491#endif
1492
mistachkinf4f327c2012-03-13 03:35:071493void sqlite3_win32_sleep(DWORD milliseconds){
1494#if SQLITE_OS_WINRT
1495 if ( sleepObj==NULL ){
1496 sleepObj = osCreateEventExW(NULL, NULL, CREATE_EVENT_MANUAL_RESET,
1497 SYNCHRONIZE);
1498 }
1499 assert( sleepObj!=NULL );
1500 osWaitForSingleObjectEx(sleepObj, milliseconds, FALSE);
1501#else
1502 osSleep(milliseconds);
1503#endif
1504}
1505
mistachkin92c2e0d2014-10-16 18:34:501506#if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \
1507 SQLITE_THREADSAFE>0
mistachkinb1ac2bc2014-07-29 16:37:531508DWORD sqlite3Win32Wait(HANDLE hObject){
1509 DWORD rc;
1510 while( (rc = osWaitForSingleObjectEx(hObject, INFINITE,
1511 TRUE))==WAIT_IO_COMPLETION ){}
1512 return rc;
1513}
mistachkin30c633a2014-09-05 05:58:371514#endif
mistachkinb1ac2bc2014-07-29 16:37:531515
drh7acec682012-03-01 21:19:391516/*
drhcc78fea2006-01-06 16:17:051517** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
1518** or WinCE. Return false (zero) for Win95, Win98, or WinME.
drhc0929982005-09-05 19:08:291519**
1520** Here is an interesting observation: Win95, Win98, and WinME lack
1521** the LockFileEx() API. But we can still statically link against that
shane50daafc2009-03-05 05:54:551522** API as long as we don't call it when running Win95/98/ME. A call to
drhc0929982005-09-05 19:08:291523** this routine is used to determine if the host is Win95/98/ME or
1524** WinNT/2K/XP so that we will know whether or not we can safely call
1525** the LockFileEx() API.
1526*/
mistachkinb8af6a22013-09-13 23:27:391527
mistachkind5be6f02016-01-27 07:28:331528#if !SQLITE_WIN32_GETVERSIONEX
mistachkin0f7e08e2013-11-27 03:01:341529# define osIsNT() (1)
1530#elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI)
mistachkinb324bc72013-08-28 02:37:291531# define osIsNT() (1)
mistachkinc60941f2012-09-13 01:51:021532#elif !defined(SQLITE_WIN32_HAS_WIDE)
mistachkinb324bc72013-08-28 02:37:291533# define osIsNT() (0)
drhcc78fea2006-01-06 16:17:051534#else
mistachkin202cb642014-07-31 18:54:011535# define osIsNT() ((sqlite3_os_type==2) || sqlite3_win32_is_nt())
mistachkind6918652014-07-29 05:49:021536#endif
1537
1538/*
1539** This function determines if the machine is running a version of Windows
1540** based on the NT kernel.
1541*/
1542int sqlite3_win32_is_nt(void){
mistachkincf4200a2014-08-21 19:11:171543#if SQLITE_OS_WINRT
1544 /*
1545 ** NOTE: The WinRT sub-platform is always assumed to be based on the NT
1546 ** kernel.
1547 */
1548 return 1;
mistachkind5be6f02016-01-27 07:28:331549#elif SQLITE_WIN32_GETVERSIONEX
mistachkin202cb642014-07-31 18:54:011550 if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){
mistachkin31753c82014-08-22 19:12:161551#if defined(SQLITE_WIN32_HAS_ANSI)
mistachkind6918652014-07-29 05:49:021552 OSVERSIONINFOA sInfo;
1553 sInfo.dwOSVersionInfoSize = sizeof(sInfo);
1554 osGetVersionExA(&sInfo);
mistachkin202cb642014-07-31 18:54:011555 osInterlockedCompareExchange(&sqlite3_os_type,
1556 (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
mistachkin31753c82014-08-22 19:12:161557#elif defined(SQLITE_WIN32_HAS_WIDE)
1558 OSVERSIONINFOW sInfo;
1559 sInfo.dwOSVersionInfoSize = sizeof(sInfo);
1560 osGetVersionExW(&sInfo);
1561 osInterlockedCompareExchange(&sqlite3_os_type,
1562 (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
mistachkin4eb4fef2014-08-12 16:13:371563#endif
drhc0929982005-09-05 19:08:291564 }
mistachkin202cb642014-07-31 18:54:011565 return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
mistachkinf0740a92014-08-11 17:51:231566#elif SQLITE_TEST
dan093c2132024-12-04 18:27:131567 return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2
1568 || osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0
1569 ;
mistachkin91d12492014-08-11 17:38:381570#else
mistachkincf4200a2014-08-21 19:11:171571 /*
1572 ** NOTE: All sub-platforms where the GetVersionEx[AW] functions are
1573 ** deprecated are always assumed to be based on the NT kernel.
1574 */
mistachkin91d12492014-08-11 17:38:381575 return 1;
1576#endif
mistachkind6918652014-07-29 05:49:021577}
drhcc78fea2006-01-06 16:17:051578
mistachkin1b186a92011-08-24 16:13:571579#ifdef SQLITE_WIN32_MALLOC
1580/*
1581** Allocate nBytes of memory.
1582*/
1583static void *winMemMalloc(int nBytes){
1584 HANDLE hHeap;
mistachkin468690e2011-08-24 17:42:221585 void *p;
mistachkin1b186a92011-08-24 16:13:571586
mistachkin468690e2011-08-24 17:42:221587 winMemAssertMagic();
1588 hHeap = winMemGetHeap();
mistachkin1b186a92011-08-24 16:13:571589 assert( hHeap!=0 );
1590 assert( hHeap!=INVALID_HANDLE_VALUE );
mistachkine8c9a182012-03-14 20:20:371591#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
mistachkine8f91052013-11-08 18:13:481592 assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
mistachkin1b186a92011-08-24 16:13:571593#endif
1594 assert( nBytes>=0 );
mistachkin318507b2011-11-11 22:08:541595 p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
mistachkin468690e2011-08-24 17:42:221596 if( !p ){
mistachkina9cb5be2013-09-12 02:09:051597 sqlite3_log(SQLITE_NOMEM, "failed to HeapAlloc %u bytes (%lu), heap=%p",
mistachkin318507b2011-11-11 22:08:541598 nBytes, osGetLastError(), (void*)hHeap);
mistachkin468690e2011-08-24 17:42:221599 }
1600 return p;
mistachkin1b186a92011-08-24 16:13:571601}
1602
1603/*
1604** Free memory.
1605*/
1606static void winMemFree(void *pPrior){
1607 HANDLE hHeap;
1608
mistachkin468690e2011-08-24 17:42:221609 winMemAssertMagic();
1610 hHeap = winMemGetHeap();
mistachkin1b186a92011-08-24 16:13:571611 assert( hHeap!=0 );
1612 assert( hHeap!=INVALID_HANDLE_VALUE );
mistachkine8c9a182012-03-14 20:20:371613#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
mistachkine8f91052013-11-08 18:13:481614 assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) );
mistachkin1b186a92011-08-24 16:13:571615#endif
mistachkin468690e2011-08-24 17:42:221616 if( !pPrior ) return; /* Passing NULL to HeapFree is undefined. */
mistachkin318507b2011-11-11 22:08:541617 if( !osHeapFree(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ){
mistachkina9cb5be2013-09-12 02:09:051618 sqlite3_log(SQLITE_NOMEM, "failed to HeapFree block %p (%lu), heap=%p",
mistachkin318507b2011-11-11 22:08:541619 pPrior, osGetLastError(), (void*)hHeap);
mistachkin468690e2011-08-24 17:42:221620 }
mistachkin1b186a92011-08-24 16:13:571621}
1622
1623/*
1624** Change the size of an existing memory allocation
1625*/
1626static void *winMemRealloc(void *pPrior, int nBytes){
1627 HANDLE hHeap;
mistachkin468690e2011-08-24 17:42:221628 void *p;
mistachkin1b186a92011-08-24 16:13:571629
mistachkin468690e2011-08-24 17:42:221630 winMemAssertMagic();
1631 hHeap = winMemGetHeap();
mistachkin1b186a92011-08-24 16:13:571632 assert( hHeap!=0 );
1633 assert( hHeap!=INVALID_HANDLE_VALUE );
mistachkine8c9a182012-03-14 20:20:371634#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
mistachkine8f91052013-11-08 18:13:481635 assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) );
mistachkin1b186a92011-08-24 16:13:571636#endif
1637 assert( nBytes>=0 );
mistachkin468690e2011-08-24 17:42:221638 if( !pPrior ){
mistachkin318507b2011-11-11 22:08:541639 p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
mistachkin468690e2011-08-24 17:42:221640 }else{
mistachkin318507b2011-11-11 22:08:541641 p = osHeapReAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior, (SIZE_T)nBytes);
mistachkin468690e2011-08-24 17:42:221642 }
1643 if( !p ){
mistachkina9cb5be2013-09-12 02:09:051644 sqlite3_log(SQLITE_NOMEM, "failed to %s %u bytes (%lu), heap=%p",
mistachkin318507b2011-11-11 22:08:541645 pPrior ? "HeapReAlloc" : "HeapAlloc", nBytes, osGetLastError(),
1646 (void*)hHeap);
mistachkin468690e2011-08-24 17:42:221647 }
1648 return p;
mistachkin1b186a92011-08-24 16:13:571649}
1650
1651/*
1652** Return the size of an outstanding allocation, in bytes.
1653*/
1654static int winMemSize(void *p){
1655 HANDLE hHeap;
1656 SIZE_T n;
1657
mistachkin468690e2011-08-24 17:42:221658 winMemAssertMagic();
1659 hHeap = winMemGetHeap();
mistachkin1b186a92011-08-24 16:13:571660 assert( hHeap!=0 );
1661 assert( hHeap!=INVALID_HANDLE_VALUE );
mistachkine8c9a182012-03-14 20:20:371662#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
mistachkin055f1652013-11-11 01:42:101663 assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, p) );
mistachkin1b186a92011-08-24 16:13:571664#endif
mistachkin468690e2011-08-24 17:42:221665 if( !p ) return 0;
mistachkin318507b2011-11-11 22:08:541666 n = osHeapSize(hHeap, SQLITE_WIN32_HEAP_FLAGS, p);
mistachkin468690e2011-08-24 17:42:221667 if( n==(SIZE_T)-1 ){
mistachkina9cb5be2013-09-12 02:09:051668 sqlite3_log(SQLITE_NOMEM, "failed to HeapSize block %p (%lu), heap=%p",
mistachkin318507b2011-11-11 22:08:541669 p, osGetLastError(), (void*)hHeap);
mistachkin468690e2011-08-24 17:42:221670 return 0;
1671 }
mistachkin1b186a92011-08-24 16:13:571672 return (int)n;
1673}
1674
1675/*
1676** Round up a request size to the next valid allocation size.
1677*/
1678static int winMemRoundup(int n){
1679 return n;
1680}
1681
1682/*
1683** Initialize this module.
1684*/
1685static int winMemInit(void *pAppData){
1686 winMemData *pWinMemData = (winMemData *)pAppData;
1687
mistachkin468690e2011-08-24 17:42:221688 if( !pWinMemData ) return SQLITE_ERROR;
mistachkine8f91052013-11-08 18:13:481689 assert( pWinMemData->magic1==WINMEM_MAGIC1 );
1690 assert( pWinMemData->magic2==WINMEM_MAGIC2 );
mistachkin0df898e2012-03-14 20:17:341691
mistachkin40c471d2012-03-15 03:40:591692#if !SQLITE_OS_WINRT && SQLITE_WIN32_HEAP_CREATE
mistachkin468690e2011-08-24 17:42:221693 if( !pWinMemData->hHeap ){
mistachkinac1f1042013-11-23 00:27:291694 DWORD dwInitialSize = SQLITE_WIN32_HEAP_INIT_SIZE;
1695 DWORD dwMaximumSize = (DWORD)sqlite3GlobalConfig.nHeap;
1696 if( dwMaximumSize==0 ){
1697 dwMaximumSize = SQLITE_WIN32_HEAP_MAX_SIZE;
1698 }else if( dwInitialSize>dwMaximumSize ){
1699 dwInitialSize = dwMaximumSize;
1700 }
mistachkin318507b2011-11-11 22:08:541701 pWinMemData->hHeap = osHeapCreate(SQLITE_WIN32_HEAP_FLAGS,
mistachkinac1f1042013-11-23 00:27:291702 dwInitialSize, dwMaximumSize);
mistachkin468690e2011-08-24 17:42:221703 if( !pWinMemData->hHeap ){
1704 sqlite3_log(SQLITE_NOMEM,
mistachkinac1f1042013-11-23 00:27:291705 "failed to HeapCreate (%lu), flags=%u, initSize=%lu, maxSize=%lu",
1706 osGetLastError(), SQLITE_WIN32_HEAP_FLAGS, dwInitialSize,
1707 dwMaximumSize);
mistachkinfad30392016-02-13 23:43:461708 return SQLITE_NOMEM_BKPT;
mistachkin1b186a92011-08-24 16:13:571709 }
1710 pWinMemData->bOwned = TRUE;
mistachkin0df898e2012-03-14 20:17:341711 assert( pWinMemData->bOwned );
mistachkin1b186a92011-08-24 16:13:571712 }
mistachkin0df898e2012-03-14 20:17:341713#else
1714 pWinMemData->hHeap = osGetProcessHeap();
1715 if( !pWinMemData->hHeap ){
1716 sqlite3_log(SQLITE_NOMEM,
mistachkina9cb5be2013-09-12 02:09:051717 "failed to GetProcessHeap (%lu)", osGetLastError());
mistachkinfad30392016-02-13 23:43:461718 return SQLITE_NOMEM_BKPT;
mistachkin0df898e2012-03-14 20:17:341719 }
1720 pWinMemData->bOwned = FALSE;
1721 assert( !pWinMemData->bOwned );
1722#endif
mistachkin1b186a92011-08-24 16:13:571723 assert( pWinMemData->hHeap!=0 );
1724 assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE );
mistachkine8c9a182012-03-14 20:20:371725#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
mistachkin318507b2011-11-11 22:08:541726 assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
mistachkin1b186a92011-08-24 16:13:571727#endif
1728 return SQLITE_OK;
1729}
1730
1731/*
1732** Deinitialize this module.
1733*/
1734static void winMemShutdown(void *pAppData){
1735 winMemData *pWinMemData = (winMemData *)pAppData;
1736
mistachkin468690e2011-08-24 17:42:221737 if( !pWinMemData ) return;
mistachkine8f91052013-11-08 18:13:481738 assert( pWinMemData->magic1==WINMEM_MAGIC1 );
1739 assert( pWinMemData->magic2==WINMEM_MAGIC2 );
1740
mistachkin468690e2011-08-24 17:42:221741 if( pWinMemData->hHeap ){
mistachkin1b186a92011-08-24 16:13:571742 assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE );
mistachkine8c9a182012-03-14 20:20:371743#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
mistachkin318507b2011-11-11 22:08:541744 assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
mistachkin1b186a92011-08-24 16:13:571745#endif
mistachkin468690e2011-08-24 17:42:221746 if( pWinMemData->bOwned ){
mistachkin318507b2011-11-11 22:08:541747 if( !osHeapDestroy(pWinMemData->hHeap) ){
mistachkina9cb5be2013-09-12 02:09:051748 sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%lu), heap=%p",
mistachkin318507b2011-11-11 22:08:541749 osGetLastError(), (void*)pWinMemData->hHeap);
mistachkin1b186a92011-08-24 16:13:571750 }
1751 pWinMemData->bOwned = FALSE;
1752 }
1753 pWinMemData->hHeap = NULL;
1754 }
1755}
1756
1757/*
1758** Populate the low-level memory allocation function pointers in
1759** sqlite3GlobalConfig.m with pointers to the routines in this file. The
1760** arguments specify the block of memory to manage.
1761**
1762** This routine is only called by sqlite3_config(), and therefore
1763** is not required to be threadsafe (it is not).
1764*/
1765const sqlite3_mem_methods *sqlite3MemGetWin32(void){
1766 static const sqlite3_mem_methods winMemMethods = {
1767 winMemMalloc,
1768 winMemFree,
1769 winMemRealloc,
1770 winMemSize,
1771 winMemRoundup,
1772 winMemInit,
1773 winMemShutdown,
1774 &win_mem_data
1775 };
1776 return &winMemMethods;
1777}
1778
1779void sqlite3MemSetDefault(void){
1780 sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetWin32());
1781}
1782#endif /* SQLITE_WIN32_MALLOC */
1783
stephan42e5ceb2025-03-10 15:15:131784#ifdef _WIN32
drhc0929982005-09-05 19:08:291785/*
mistachkin12931202016-04-04 02:05:461786** Convert a UTF-8 string to Microsoft Unicode.
drh584c0942006-12-21 03:20:401787**
mistachkin12931202016-04-04 02:05:461788** Space to hold the returned string is obtained from sqlite3_malloc().
drhc0929982005-09-05 19:08:291789*/
mistachkin5daed672016-04-03 22:44:161790static LPWSTR winUtf8ToUnicode(const char *zText){
drhe3dd8bb2006-02-27 23:44:351791 int nChar;
mistachkin5daed672016-04-03 22:44:161792 LPWSTR zWideText;
drhc0929982005-09-05 19:08:291793
mistachkin5daed672016-04-03 22:44:161794 nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, NULL, 0);
mistachkin6ca514b2011-12-14 00:37:451795 if( nChar==0 ){
1796 return 0;
1797 }
mistachkin5daed672016-04-03 22:44:161798 zWideText = sqlite3MallocZero( nChar*sizeof(WCHAR) );
1799 if( zWideText==0 ){
drhc0929982005-09-05 19:08:291800 return 0;
1801 }
mistachkin5daed672016-04-03 22:44:161802 nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, zWideText,
mistachkin318507b2011-11-11 22:08:541803 nChar);
drhe3dd8bb2006-02-27 23:44:351804 if( nChar==0 ){
mistachkin5daed672016-04-03 22:44:161805 sqlite3_free(zWideText);
1806 zWideText = 0;
drhc0929982005-09-05 19:08:291807 }
mistachkin5daed672016-04-03 22:44:161808 return zWideText;
drhc0929982005-09-05 19:08:291809}
stephan42e5ceb2025-03-10 15:15:131810#endif /* _WIN32 */
drhc0929982005-09-05 19:08:291811
1812/*
mistachkin12931202016-04-04 02:05:461813** Convert a Microsoft Unicode string to UTF-8.
1814**
1815** Space to hold the returned string is obtained from sqlite3_malloc().
drhc0929982005-09-05 19:08:291816*/
mistachkin5daed672016-04-03 22:44:161817static char *winUnicodeToUtf8(LPCWSTR zWideText){
drhc0929982005-09-05 19:08:291818 int nByte;
mistachkin5daed672016-04-03 22:44:161819 char *zText;
drhc0929982005-09-05 19:08:291820
mistachkin5daed672016-04-03 22:44:161821 nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideText, -1, 0, 0, 0, 0);
mistachkin6ca514b2011-12-14 00:37:451822 if( nByte == 0 ){
1823 return 0;
1824 }
mistachkin5daed672016-04-03 22:44:161825 zText = sqlite3MallocZero( nByte );
1826 if( zText==0 ){
drhc0929982005-09-05 19:08:291827 return 0;
1828 }
mistachkin5daed672016-04-03 22:44:161829 nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideText, -1, zText, nByte,
mistachkin318507b2011-11-11 22:08:541830 0, 0);
drhc0929982005-09-05 19:08:291831 if( nByte == 0 ){
mistachkin5daed672016-04-03 22:44:161832 sqlite3_free(zText);
1833 zText = 0;
drhc0929982005-09-05 19:08:291834 }
mistachkin5daed672016-04-03 22:44:161835 return zText;
drhc0929982005-09-05 19:08:291836}
1837
drh371de5a2006-10-30 13:37:221838/*
mistachkin12931202016-04-04 02:05:461839** Convert an ANSI string to Microsoft Unicode, using the ANSI or OEM
1840** code page.
mistachkin17835a52014-08-06 03:06:011841**
mistachkin12931202016-04-04 02:05:461842** Space to hold the returned string is obtained from sqlite3_malloc().
drh371de5a2006-10-30 13:37:221843*/
mistachkin5daed672016-04-03 22:44:161844static LPWSTR winMbcsToUnicode(const char *zText, int useAnsi){
stephan7b9407a2025-03-07 06:54:041845 int nWideChar;
mistachkin12931202016-04-04 02:05:461846 LPWSTR zMbcsText;
mistachkin5daed672016-04-03 22:44:161847 int codepage = useAnsi ? CP_ACP : CP_OEMCP;
drh371de5a2006-10-30 13:37:221848
stephan7b9407a2025-03-07 06:54:041849 nWideChar = osMultiByteToWideChar(codepage, 0, zText, -1, NULL,
1850 0);
1851 if( nWideChar==0 ){
mistachkin6ca514b2011-12-14 00:37:451852 return 0;
1853 }
stephan7b9407a2025-03-07 06:54:041854 zMbcsText = sqlite3MallocZero( nWideChar*sizeof(WCHAR) );
mistachkin12931202016-04-04 02:05:461855 if( zMbcsText==0 ){
drh371de5a2006-10-30 13:37:221856 return 0;
1857 }
stephan7b9407a2025-03-07 06:54:041858 nWideChar = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText,
1859 nWideChar);
1860 if( nWideChar==0 ){
mistachkin12931202016-04-04 02:05:461861 sqlite3_free(zMbcsText);
1862 zMbcsText = 0;
drh371de5a2006-10-30 13:37:221863 }
mistachkin12931202016-04-04 02:05:461864 return zMbcsText;
drh371de5a2006-10-30 13:37:221865}
1866
stephan7b9407a2025-03-07 06:54:041867#ifdef _WIN32
drh371de5a2006-10-30 13:37:221868/*
mistachkin12931202016-04-04 02:05:461869** Convert a Microsoft Unicode string to a multi-byte character string,
1870** using the ANSI or OEM code page.
drh584c0942006-12-21 03:20:401871**
mistachkin12931202016-04-04 02:05:461872** Space to hold the returned string is obtained from sqlite3_malloc().
drh371de5a2006-10-30 13:37:221873*/
mistachkin5daed672016-04-03 22:44:161874static char *winUnicodeToMbcs(LPCWSTR zWideText, int useAnsi){
drh371de5a2006-10-30 13:37:221875 int nByte;
mistachkin5daed672016-04-03 22:44:161876 char *zText;
1877 int codepage = useAnsi ? CP_ACP : CP_OEMCP;
drh371de5a2006-10-30 13:37:221878
mistachkin5daed672016-04-03 22:44:161879 nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, 0, 0, 0, 0);
mistachkin6ca514b2011-12-14 00:37:451880 if( nByte == 0 ){
1881 return 0;
1882 }
mistachkin5daed672016-04-03 22:44:161883 zText = sqlite3MallocZero( nByte );
1884 if( zText==0 ){
drh371de5a2006-10-30 13:37:221885 return 0;
1886 }
mistachkin5daed672016-04-03 22:44:161887 nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, zText,
mistachkin318507b2011-11-11 22:08:541888 nByte, 0, 0);
drh371de5a2006-10-30 13:37:221889 if( nByte == 0 ){
mistachkin5daed672016-04-03 22:44:161890 sqlite3_free(zText);
1891 zText = 0;
drh371de5a2006-10-30 13:37:221892 }
mistachkin5daed672016-04-03 22:44:161893 return zText;
drh371de5a2006-10-30 13:37:221894}
stephan7b9407a2025-03-07 06:54:041895#endif /* _WIN32 */
drh371de5a2006-10-30 13:37:221896
1897/*
mistachkin12931202016-04-04 02:05:461898** Convert a multi-byte character string to UTF-8.
1899**
1900** Space to hold the returned string is obtained from sqlite3_malloc().
drh371de5a2006-10-30 13:37:221901*/
mistachkin12931202016-04-04 02:05:461902static char *winMbcsToUtf8(const char *zText, int useAnsi){
1903 char *zTextUtf8;
mistachkin318507b2011-11-11 22:08:541904 LPWSTR zTmpWide;
drh371de5a2006-10-30 13:37:221905
mistachkin12931202016-04-04 02:05:461906 zTmpWide = winMbcsToUnicode(zText, useAnsi);
drh371de5a2006-10-30 13:37:221907 if( zTmpWide==0 ){
1908 return 0;
1909 }
mistachkin12931202016-04-04 02:05:461910 zTextUtf8 = winUnicodeToUtf8(zTmpWide);
mistachkin5f075382011-11-11 23:31:041911 sqlite3_free(zTmpWide);
mistachkin12931202016-04-04 02:05:461912 return zTextUtf8;
drh371de5a2006-10-30 13:37:221913}
1914
stephan7b9407a2025-03-07 06:54:041915#ifdef _WIN32
drh371de5a2006-10-30 13:37:221916/*
mistachkin12931202016-04-04 02:05:461917** Convert a UTF-8 string to a multi-byte character string.
1918**
1919** Space to hold the returned string is obtained from sqlite3_malloc().
drh371de5a2006-10-30 13:37:221920*/
mistachkin12931202016-04-04 02:05:461921static char *winUtf8ToMbcs(const char *zText, int useAnsi){
1922 char *zTextMbcs;
mistachkin318507b2011-11-11 22:08:541923 LPWSTR zTmpWide;
drh371de5a2006-10-30 13:37:221924
mistachkin12931202016-04-04 02:05:461925 zTmpWide = winUtf8ToUnicode(zText);
drh371de5a2006-10-30 13:37:221926 if( zTmpWide==0 ){
1927 return 0;
1928 }
mistachkin12931202016-04-04 02:05:461929 zTextMbcs = winUnicodeToMbcs(zTmpWide, useAnsi);
mistachkin5f075382011-11-11 23:31:041930 sqlite3_free(zTmpWide);
mistachkin12931202016-04-04 02:05:461931 return zTextMbcs;
1932}
1933
1934/*
1935** This is a public wrapper for the winUtf8ToUnicode() function.
1936*/
1937LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText){
1938#ifdef SQLITE_ENABLE_API_ARMOR
1939 if( !zText ){
1940 (void)SQLITE_MISUSE_BKPT;
1941 return 0;
1942 }
1943#endif
1944#ifndef SQLITE_OMIT_AUTOINIT
1945 if( sqlite3_initialize() ) return 0;
1946#endif
1947 return winUtf8ToUnicode(zText);
1948}
1949
1950/*
1951** This is a public wrapper for the winUnicodeToUtf8() function.
1952*/
1953char *sqlite3_win32_unicode_to_utf8(LPCWSTR zWideText){
1954#ifdef SQLITE_ENABLE_API_ARMOR
1955 if( !zWideText ){
1956 (void)SQLITE_MISUSE_BKPT;
1957 return 0;
1958 }
1959#endif
1960#ifndef SQLITE_OMIT_AUTOINIT
1961 if( sqlite3_initialize() ) return 0;
1962#endif
1963 return winUnicodeToUtf8(zWideText);
1964}
stephan7b9407a2025-03-07 06:54:041965#endif /* _WIN32 */
mistachkin12931202016-04-04 02:05:461966
1967/*
1968** This is a public wrapper for the winMbcsToUtf8() function.
drh371de5a2006-10-30 13:37:221969*/
mistachkin5daed672016-04-03 22:44:161970char *sqlite3_win32_mbcs_to_utf8(const char *zText){
mistachkin12931202016-04-04 02:05:461971#ifdef SQLITE_ENABLE_API_ARMOR
1972 if( !zText ){
1973 (void)SQLITE_MISUSE_BKPT;
drh371de5a2006-10-30 13:37:221974 return 0;
1975 }
mistachkin12931202016-04-04 02:05:461976#endif
1977#ifndef SQLITE_OMIT_AUTOINIT
1978 if( sqlite3_initialize() ) return 0;
1979#endif
1980 return winMbcsToUtf8(zText, osAreFileApisANSI());
mistachkin5daed672016-04-03 22:44:161981}
1982
stephan7b9407a2025-03-07 06:54:041983#ifdef _WIN32
mistachkin5daed672016-04-03 22:44:161984/*
mistachkin12931202016-04-04 02:05:461985** This is a public wrapper for the winMbcsToUtf8() function.
mistachkin5daed672016-04-03 22:44:161986*/
mistachkin12931202016-04-04 02:05:461987char *sqlite3_win32_mbcs_to_utf8_v2(const char *zText, int useAnsi){
1988#ifdef SQLITE_ENABLE_API_ARMOR
1989 if( !zText ){
1990 (void)SQLITE_MISUSE_BKPT;
mistachkin5daed672016-04-03 22:44:161991 return 0;
1992 }
mistachkin12931202016-04-04 02:05:461993#endif
1994#ifndef SQLITE_OMIT_AUTOINIT
1995 if( sqlite3_initialize() ) return 0;
1996#endif
1997 return winMbcsToUtf8(zText, useAnsi);
mistachkin5daed672016-04-03 22:44:161998}
1999
2000/*
mistachkin12931202016-04-04 02:05:462001** This is a public wrapper for the winUtf8ToMbcs() function.
drh371de5a2006-10-30 13:37:222002*/
mistachkin5daed672016-04-03 22:44:162003char *sqlite3_win32_utf8_to_mbcs(const char *zText){
mistachkin12931202016-04-04 02:05:462004#ifdef SQLITE_ENABLE_API_ARMOR
2005 if( !zText ){
2006 (void)SQLITE_MISUSE_BKPT;
drh371de5a2006-10-30 13:37:222007 return 0;
2008 }
mistachkin12931202016-04-04 02:05:462009#endif
2010#ifndef SQLITE_OMIT_AUTOINIT
2011 if( sqlite3_initialize() ) return 0;
2012#endif
2013 return winUtf8ToMbcs(zText, osAreFileApisANSI());
mistachkin5daed672016-04-03 22:44:162014}
2015
2016/*
mistachkin12931202016-04-04 02:05:462017** This is a public wrapper for the winUtf8ToMbcs() function.
mistachkin5daed672016-04-03 22:44:162018*/
mistachkin12931202016-04-04 02:05:462019char *sqlite3_win32_utf8_to_mbcs_v2(const char *zText, int useAnsi){
2020#ifdef SQLITE_ENABLE_API_ARMOR
2021 if( !zText ){
2022 (void)SQLITE_MISUSE_BKPT;
mistachkin5daed672016-04-03 22:44:162023 return 0;
2024 }
mistachkin12931202016-04-04 02:05:462025#endif
2026#ifndef SQLITE_OMIT_AUTOINIT
2027 if( sqlite3_initialize() ) return 0;
2028#endif
2029 return winUtf8ToMbcs(zText, useAnsi);
drh371de5a2006-10-30 13:37:222030}
2031
mistachkin61540682012-08-21 23:33:452032/*
mistachkin07430a82018-05-02 03:01:502033** This function is the same as sqlite3_win32_set_directory (below); however,
2034** it accepts a UTF-8 string.
mistachkin61540682012-08-21 23:33:452035*/
mistachkin07430a82018-05-02 03:01:502036int sqlite3_win32_set_directory8(
mistachkin95d5ae12018-04-27 22:42:372037 unsigned long type, /* Identifier for directory being set or reset */
mistachkin07430a82018-05-02 03:01:502038 const char *zValue /* New value for directory being set or reset */
mistachkin95d5ae12018-04-27 22:42:372039){
mistachkin61540682012-08-21 23:33:452040 char **ppDirectory = 0;
drh6e440ab2022-09-05 18:17:032041 int rc;
mistachkin61540682012-08-21 23:33:452042#ifndef SQLITE_OMIT_AUTOINIT
drh6e440ab2022-09-05 18:17:032043 rc = sqlite3_initialize();
mistachkin61540682012-08-21 23:33:452044 if( rc ) return rc;
2045#endif
drh18a3a482022-09-02 00:36:162046 sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
mistachkin61540682012-08-21 23:33:452047 if( type==SQLITE_WIN32_DATA_DIRECTORY_TYPE ){
2048 ppDirectory = &sqlite3_data_directory;
2049 }else if( type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE ){
2050 ppDirectory = &sqlite3_temp_directory;
2051 }
2052 assert( !ppDirectory || type==SQLITE_WIN32_DATA_DIRECTORY_TYPE
2053 || type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE
2054 );
mistachkin484dbef2012-08-22 00:18:272055 assert( !ppDirectory || sqlite3MemdebugHasType(*ppDirectory, MEMTYPE_HEAP) );
mistachkin61540682012-08-21 23:33:452056 if( ppDirectory ){
mistachkin07430a82018-05-02 03:01:502057 char *zCopy = 0;
2058 if( zValue && zValue[0] ){
2059 zCopy = sqlite3_mprintf("%s", zValue);
2060 if ( zCopy==0 ){
drh18a3a482022-09-02 00:36:162061 rc = SQLITE_NOMEM_BKPT;
2062 goto set_directory8_done;
mistachkin61540682012-08-21 23:33:452063 }
2064 }
2065 sqlite3_free(*ppDirectory);
mistachkin07430a82018-05-02 03:01:502066 *ppDirectory = zCopy;
drh18a3a482022-09-02 00:36:162067 rc = SQLITE_OK;
2068 }else{
2069 rc = SQLITE_ERROR;
mistachkin61540682012-08-21 23:33:452070 }
drh18a3a482022-09-02 00:36:162071set_directory8_done:
2072 sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
2073 return rc;
mistachkin61540682012-08-21 23:33:452074}
drh50990db2011-04-13 20:26:132075
2076/*
mistachkin07430a82018-05-02 03:01:502077** This function is the same as sqlite3_win32_set_directory (below); however,
2078** it accepts a UTF-16 string.
2079*/
2080int sqlite3_win32_set_directory16(
2081 unsigned long type, /* Identifier for directory being set or reset */
2082 const void *zValue /* New value for directory being set or reset */
2083){
2084 int rc;
2085 char *zUtf8 = 0;
2086 if( zValue ){
2087 zUtf8 = sqlite3_win32_unicode_to_utf8(zValue);
2088 if( zUtf8==0 ) return SQLITE_NOMEM_BKPT;
2089 }
2090 rc = sqlite3_win32_set_directory8(type, zUtf8);
2091 if( zUtf8 ) sqlite3_free(zUtf8);
2092 return rc;
2093}
2094
2095/*
2096** This function sets the data directory or the temporary directory based on
2097** the provided arguments. The type argument must be 1 in order to set the
2098** data directory or 2 in order to set the temporary directory. The zValue
2099** argument is the name of the directory to use. The return value will be
2100** SQLITE_OK if successful.
2101*/
2102int sqlite3_win32_set_directory(
2103 unsigned long type, /* Identifier for directory being set or reset */
2104 void *zValue /* New value for directory being set or reset */
2105){
2106 return sqlite3_win32_set_directory16(type, zValue);
2107}
stephan7b9407a2025-03-07 06:54:042108#endif /* _WIN32 */
mistachkin07430a82018-05-02 03:01:502109
2110/*
mistachkinb324bc72013-08-28 02:37:292111** The return value of winGetLastErrorMsg
drh50990db2011-04-13 20:26:132112** is zero if the error message fits in the buffer, or non-zero
2113** otherwise (if the message was truncated).
2114*/
mistachkinb324bc72013-08-28 02:37:292115static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){
drh50990db2011-04-13 20:26:132116 /* FormatMessage returns 0 on failure. Otherwise it
2117 ** returns the number of TCHARs written to the output
2118 ** buffer, excluding the terminating null char.
2119 */
drh50990db2011-04-13 20:26:132120 DWORD dwLen = 0;
2121 char *zOut = 0;
2122
mistachkinb324bc72013-08-28 02:37:292123 if( osIsNT() ){
mistachkin62d19242012-03-02 23:53:542124#if SQLITE_OS_WINRT
mistachkin31706a22013-08-26 20:45:502125 WCHAR zTempWide[SQLITE_WIN32_MAX_ERRMSG_CHARS+1];
mistachkin62d19242012-03-02 23:53:542126 dwLen = osFormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
2127 FORMAT_MESSAGE_IGNORE_INSERTS,
2128 NULL,
2129 lastErrno,
2130 0,
2131 zTempWide,
mistachkin31706a22013-08-26 20:45:502132 SQLITE_WIN32_MAX_ERRMSG_CHARS,
mistachkin62d19242012-03-02 23:53:542133 0);
2134#else
mistachkin318507b2011-11-11 22:08:542135 LPWSTR zTempWide = NULL;
2136 dwLen = osFormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
2137 FORMAT_MESSAGE_FROM_SYSTEM |
2138 FORMAT_MESSAGE_IGNORE_INSERTS,
2139 NULL,
2140 lastErrno,
2141 0,
2142 (LPWSTR) &zTempWide,
2143 0,
2144 0);
mistachkin62d19242012-03-02 23:53:542145#endif
drh50990db2011-04-13 20:26:132146 if( dwLen > 0 ){
2147 /* allocate a buffer and convert to UTF8 */
mistachkin6c3c1a02011-11-12 03:17:402148 sqlite3BeginBenignMalloc();
mistachkinb324bc72013-08-28 02:37:292149 zOut = winUnicodeToUtf8(zTempWide);
mistachkin6c3c1a02011-11-12 03:17:402150 sqlite3EndBenignMalloc();
mistachkin62d19242012-03-02 23:53:542151#if !SQLITE_OS_WINRT
drh50990db2011-04-13 20:26:132152 /* free the system buffer allocated by FormatMessage */
mistachkin318507b2011-11-11 22:08:542153 osLocalFree(zTempWide);
mistachkin62d19242012-03-02 23:53:542154#endif
drh50990db2011-04-13 20:26:132155 }
drhd52ee722012-03-02 00:00:472156 }
2157#ifdef SQLITE_WIN32_HAS_ANSI
2158 else{
drh50990db2011-04-13 20:26:132159 char *zTemp = NULL;
mistachkin318507b2011-11-11 22:08:542160 dwLen = osFormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
2161 FORMAT_MESSAGE_FROM_SYSTEM |
2162 FORMAT_MESSAGE_IGNORE_INSERTS,
2163 NULL,
2164 lastErrno,
2165 0,
2166 (LPSTR) &zTemp,
2167 0,
2168 0);
drh50990db2011-04-13 20:26:132169 if( dwLen > 0 ){
2170 /* allocate a buffer and convert to UTF8 */
mistachkin6c3c1a02011-11-12 03:17:402171 sqlite3BeginBenignMalloc();
mistachkin12931202016-04-04 02:05:462172 zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI());
mistachkin6c3c1a02011-11-12 03:17:402173 sqlite3EndBenignMalloc();
drh50990db2011-04-13 20:26:132174 /* free the system buffer allocated by FormatMessage */
mistachkin318507b2011-11-11 22:08:542175 osLocalFree(zTemp);
drh50990db2011-04-13 20:26:132176 }
drh50990db2011-04-13 20:26:132177 }
drhd52ee722012-03-02 00:00:472178#endif
drh50990db2011-04-13 20:26:132179 if( 0 == dwLen ){
mistachkine84d8d32013-04-29 03:09:102180 sqlite3_snprintf(nBuf, zBuf, "OsError 0x%lx (%lu)", lastErrno, lastErrno);
drh50990db2011-04-13 20:26:132181 }else{
2182 /* copy a maximum of nBuf chars to output buffer */
2183 sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
2184 /* free the UTF8 buffer */
mistachkin5f075382011-11-11 23:31:042185 sqlite3_free(zOut);
drh50990db2011-04-13 20:26:132186 }
2187 return 0;
2188}
2189
2190/*
2191**
2192** This function - winLogErrorAtLine() - is only ever called via the macro
2193** winLogError().
2194**
2195** This routine is invoked after an error occurs in an OS function.
2196** It logs a message using sqlite3_log() containing the current value of
mistachkin17835a52014-08-06 03:06:012197** error code and, if possible, the human-readable equivalent from
drh50990db2011-04-13 20:26:132198** FormatMessage.
2199**
2200** The first argument passed to the macro should be the error code that
mistachkin17835a52014-08-06 03:06:012201** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN).
drh50990db2011-04-13 20:26:132202** The two subsequent arguments should be the name of the OS function that
mistachkind5578432012-08-25 10:01:292203** failed and the associated file-system path, if any.
drh50990db2011-04-13 20:26:132204*/
mistachkin2aef9972011-11-10 20:21:202205#define winLogError(a,b,c,d) winLogErrorAtLine(a,b,c,d,__LINE__)
drh50990db2011-04-13 20:26:132206static int winLogErrorAtLine(
2207 int errcode, /* SQLite error code */
mistachkin2aef9972011-11-10 20:21:202208 DWORD lastErrno, /* Win32 last error */
drh50990db2011-04-13 20:26:132209 const char *zFunc, /* Name of OS function that failed */
2210 const char *zPath, /* File path associated with error */
2211 int iLine /* Source line number where error occurred */
2212){
2213 char zMsg[500]; /* Human readable error text */
drh5f2dfdb2011-04-13 23:42:532214 int i; /* Loop counter */
drh50990db2011-04-13 20:26:132215
2216 zMsg[0] = 0;
mistachkinb324bc72013-08-28 02:37:292217 winGetLastErrorMsg(lastErrno, sizeof(zMsg), zMsg);
drh50990db2011-04-13 20:26:132218 assert( errcode!=SQLITE_OK );
2219 if( zPath==0 ) zPath = "";
drh5f2dfdb2011-04-13 23:42:532220 for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){}
2221 zMsg[i] = 0;
drh50990db2011-04-13 20:26:132222 sqlite3_log(errcode,
mistachkine84d8d32013-04-29 03:09:102223 "os_win.c:%d: (%lu) %s(%s) - %s",
mistachkin2aef9972011-11-10 20:21:202224 iLine, lastErrno, zFunc, zPath, zMsg
drh50990db2011-04-13 20:26:132225 );
2226
2227 return errcode;
2228}
2229
drh5d9ef0a2011-07-11 18:17:562230/*
drh52564d72011-07-12 11:04:182231** The number of times that a ReadFile(), WriteFile(), and DeleteFile()
mistachkin17835a52014-08-06 03:06:012232** will be retried following a locking error - probably caused by
drh52564d72011-07-12 11:04:182233** antivirus software. Also the initial delay before the first retry.
2234** The delay increases linearly with each retry.
drh5d9ef0a2011-07-11 18:17:562235*/
2236#ifndef SQLITE_WIN32_IOERR_RETRY
drh52564d72011-07-12 11:04:182237# define SQLITE_WIN32_IOERR_RETRY 10
2238#endif
2239#ifndef SQLITE_WIN32_IOERR_RETRY_DELAY
2240# define SQLITE_WIN32_IOERR_RETRY_DELAY 25
drh5d9ef0a2011-07-11 18:17:562241#endif
mistachkinb324bc72013-08-28 02:37:292242static int winIoerrRetry = SQLITE_WIN32_IOERR_RETRY;
2243static int winIoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY;
drh5d9ef0a2011-07-11 18:17:562244
2245/*
mistachkin491451d2014-02-18 05:18:362246** The "winIoerrCanRetry1" macro is used to determine if a particular I/O
2247** error code obtained via GetLastError() is eligible to be retried. It
2248** must accept the error code DWORD as its only argument and should return
2249** non-zero if the error code is transient in nature and the operation
2250** responsible for generating the original error might succeed upon being
2251** retried. The argument to this macro should be a variable.
2252**
2253** Additionally, a macro named "winIoerrCanRetry2" may be defined. If it
2254** is defined, it will be consulted only when the macro "winIoerrCanRetry1"
2255** returns zero. The "winIoerrCanRetry2" macro is completely optional and
2256** may be used to include additional error codes in the set that should
2257** result in the failing I/O operation being retried by the caller. If
2258** defined, the "winIoerrCanRetry2" macro must exhibit external semantics
2259** identical to those of the "winIoerrCanRetry1" macro.
2260*/
2261#if !defined(winIoerrCanRetry1)
2262#define winIoerrCanRetry1(a) (((a)==ERROR_ACCESS_DENIED) || \
2263 ((a)==ERROR_SHARING_VIOLATION) || \
2264 ((a)==ERROR_LOCK_VIOLATION) || \
2265 ((a)==ERROR_DEV_NOT_EXIST) || \
2266 ((a)==ERROR_NETNAME_DELETED) || \
2267 ((a)==ERROR_SEM_TIMEOUT) || \
2268 ((a)==ERROR_NETWORK_UNREACHABLE))
2269#endif
2270
2271/*
drh5d9ef0a2011-07-11 18:17:562272** If a ReadFile() or WriteFile() error occurs, invoke this routine
2273** to see if it should be retried. Return TRUE to retry. Return FALSE
2274** to give up with an error.
2275*/
mistachkinb324bc72013-08-28 02:37:292276static int winRetryIoerr(int *pnRetry, DWORD *pError){
mistachkind1ef9b62011-11-21 00:54:372277 DWORD e = osGetLastError();
mistachkinb324bc72013-08-28 02:37:292278 if( *pnRetry>=winIoerrRetry ){
mistachkind1ef9b62011-11-21 00:54:372279 if( pError ){
2280 *pError = e;
2281 }
drh5d9ef0a2011-07-11 18:17:562282 return 0;
2283 }
mistachkin491451d2014-02-18 05:18:362284 if( winIoerrCanRetry1(e) ){
mistachkinb324bc72013-08-28 02:37:292285 sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry));
drh5d9ef0a2011-07-11 18:17:562286 ++*pnRetry;
2287 return 1;
2288 }
mistachkin491451d2014-02-18 05:18:362289#if defined(winIoerrCanRetry2)
2290 else if( winIoerrCanRetry2(e) ){
2291 sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry));
2292 ++*pnRetry;
2293 return 1;
2294 }
2295#endif
mistachkind1ef9b62011-11-21 00:54:372296 if( pError ){
2297 *pError = e;
2298 }
drh5d9ef0a2011-07-11 18:17:562299 return 0;
2300}
2301
drha32ad842011-07-12 13:51:052302/*
2303** Log a I/O error retry episode.
2304*/
drh21aa6a12015-03-26 15:27:322305static void winLogIoerr(int nRetry, int lineno){
drha32ad842011-07-12 13:51:052306 if( nRetry ){
drh8237f6d2015-03-31 17:32:062307 sqlite3_log(SQLITE_NOTICE,
drh21aa6a12015-03-26 15:27:322308 "delayed %dms for lock/sharing conflict at line %d",
2309 winIoerrRetryDelay*nRetry*(nRetry+1)/2, lineno
drha32ad842011-07-12 13:51:052310 );
2311 }
2312}
2313
mistachkin6cc16fc2016-01-23 01:54:152314/*
mistachkin8366ddf2016-04-12 16:11:522315** This #if does not rely on the SQLITE_OS_WINCE define because the
2316** corresponding section in "date.c" cannot use it.
drh72aead82006-01-23 15:54:252317*/
mistachkin0cedb962016-04-11 22:45:452318#if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \
mistachkin0e188e12016-04-11 22:10:262319 (!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API)
mistachkin8366ddf2016-04-12 16:11:522320/*
2321** The MSVC CRT on Windows CE may not have a localtime() function.
2322** So define a substitute.
2323*/
mistachkin0cedb962016-04-11 22:45:452324# include <time.h>
drh72aead82006-01-23 15:54:252325struct tm *__cdecl localtime(const time_t *t)
2326{
2327 static struct tm y;
2328 FILETIME uTm, lTm;
2329 SYSTEMTIME pTm;
drhc51250a2007-09-20 14:39:232330 sqlite3_int64 t64;
drh72aead82006-01-23 15:54:252331 t64 = *t;
2332 t64 = (t64 + 11644473600)*10000000;
shane11bb41f2009-09-10 20:23:302333 uTm.dwLowDateTime = (DWORD)(t64 & 0xFFFFFFFF);
2334 uTm.dwHighDateTime= (DWORD)(t64 >> 32);
mistachkin318507b2011-11-11 22:08:542335 osFileTimeToLocalFileTime(&uTm,&lTm);
2336 osFileTimeToSystemTime(&lTm,&pTm);
drh72aead82006-01-23 15:54:252337 y.tm_year = pTm.wYear - 1900;
2338 y.tm_mon = pTm.wMonth - 1;
2339 y.tm_wday = pTm.wDayOfWeek;
2340 y.tm_mday = pTm.wDay;
2341 y.tm_hour = pTm.wHour;
2342 y.tm_min = pTm.wMinute;
2343 y.tm_sec = pTm.wSecond;
2344 return &y;
2345}
mistachkin2bfe1df2013-02-07 05:12:252346#endif
drh72aead82006-01-23 15:54:252347
mistachkin6cc16fc2016-01-23 01:54:152348#if SQLITE_OS_WINCE
2349/*************************************************************************
2350** This section contains code for WinCE only.
2351*/
shane11bb41f2009-09-10 20:23:302352#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
drh72aead82006-01-23 15:54:252353
2354/*
2355** Acquire a lock on the handle h
2356*/
2357static void winceMutexAcquire(HANDLE h){
2358 DWORD dwErr;
2359 do {
mistachkin75b70a22012-03-02 13:47:162360 dwErr = osWaitForSingleObject(h, INFINITE);
drh72aead82006-01-23 15:54:252361 } while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED);
2362}
2363/*
2364** Release a lock acquired by winceMutexAcquire()
2365*/
2366#define winceMutexRelease(h) ReleaseMutex(h)
2367
2368/*
2369** Create the mutex and shared memory used for locking in the file
2370** descriptor pFile
2371*/
mistachkin7e87eae2013-02-12 09:46:482372static int winceCreateLock(const char *zFilename, winFile *pFile){
mistachkin318507b2011-11-11 22:08:542373 LPWSTR zTok;
mistachkin5f075382011-11-11 23:31:042374 LPWSTR zName;
mistachkin7e87eae2013-02-12 09:46:482375 DWORD lastErrno;
2376 BOOL bLogged = FALSE;
drh72aead82006-01-23 15:54:252377 BOOL bInit = TRUE;
2378
mistachkinb324bc72013-08-28 02:37:292379 zName = winUtf8ToUnicode(zFilename);
mistachkin5f075382011-11-11 23:31:042380 if( zName==0 ){
2381 /* out of memory */
mistachkinfad30392016-02-13 23:43:462382 return SQLITE_IOERR_NOMEM_BKPT;
mistachkin5f075382011-11-11 23:31:042383 }
2384
drh72aead82006-01-23 15:54:252385 /* Initialize the local lockdata */
mistachkin318507b2011-11-11 22:08:542386 memset(&pFile->local, 0, sizeof(pFile->local));
drh72aead82006-01-23 15:54:252387
2388 /* Replace the backslashes from the filename and lowercase it
2389 ** to derive a mutex name. */
mistachkin318507b2011-11-11 22:08:542390 zTok = osCharLowerW(zName);
drh72aead82006-01-23 15:54:252391 for (;*zTok;zTok++){
2392 if (*zTok == '\\') *zTok = '_';
2393 }
2394
2395 /* Create/open the named mutex */
mistachkin318507b2011-11-11 22:08:542396 pFile->hMutex = osCreateMutexW(NULL, FALSE, zName);
drh72aead82006-01-23 15:54:252397 if (!pFile->hMutex){
mistachkin318507b2011-11-11 22:08:542398 pFile->lastErrno = osGetLastError();
mistachkin5f075382011-11-11 23:31:042399 sqlite3_free(zName);
mistachkin9f11ef12013-08-31 02:48:562400 return winLogError(SQLITE_IOERR, pFile->lastErrno,
2401 "winceCreateLock1", zFilename);
drh72aead82006-01-23 15:54:252402 }
2403
2404 /* Acquire the mutex before continuing */
2405 winceMutexAcquire(pFile->hMutex);
mistachkin17835a52014-08-06 03:06:012406
2407 /* Since the names of named mutexes, semaphores, file mappings etc are
drh72aead82006-01-23 15:54:252408 ** case-sensitive, take advantage of that by uppercasing the mutex name
2409 ** and using that as the shared filemapping name.
2410 */
mistachkin318507b2011-11-11 22:08:542411 osCharUpperW(zName);
2412 pFile->hShared = osCreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
2413 PAGE_READWRITE, 0, sizeof(winceLock),
mistachkin17835a52014-08-06 03:06:012414 zName);
drh72aead82006-01-23 15:54:252415
mistachkin17835a52014-08-06 03:06:012416 /* Set a flag that indicates we're the first to create the memory so it
drh72aead82006-01-23 15:54:252417 ** must be zero-initialized */
mistachkin7e87eae2013-02-12 09:46:482418 lastErrno = osGetLastError();
2419 if (lastErrno == ERROR_ALREADY_EXISTS){
drh72aead82006-01-23 15:54:252420 bInit = FALSE;
2421 }
2422
mistachkin5f075382011-11-11 23:31:042423 sqlite3_free(zName);
drh72aead82006-01-23 15:54:252424
2425 /* If we succeeded in making the shared memory handle, map it. */
mistachkin7e87eae2013-02-12 09:46:482426 if( pFile->hShared ){
mistachkin17835a52014-08-06 03:06:012427 pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared,
drh72aead82006-01-23 15:54:252428 FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock));
2429 /* If mapping failed, close the shared memory handle and erase it */
mistachkin7e87eae2013-02-12 09:46:482430 if( !pFile->shared ){
mistachkin318507b2011-11-11 22:08:542431 pFile->lastErrno = osGetLastError();
mistachkin7e87eae2013-02-12 09:46:482432 winLogError(SQLITE_IOERR, pFile->lastErrno,
2433 "winceCreateLock2", zFilename);
2434 bLogged = TRUE;
mistachkin318507b2011-11-11 22:08:542435 osCloseHandle(pFile->hShared);
drh72aead82006-01-23 15:54:252436 pFile->hShared = NULL;
2437 }
2438 }
2439
2440 /* If shared memory could not be created, then close the mutex and fail */
mistachkin7e87eae2013-02-12 09:46:482441 if( pFile->hShared==NULL ){
2442 if( !bLogged ){
2443 pFile->lastErrno = lastErrno;
2444 winLogError(SQLITE_IOERR, pFile->lastErrno,
2445 "winceCreateLock3", zFilename);
2446 bLogged = TRUE;
2447 }
drh72aead82006-01-23 15:54:252448 winceMutexRelease(pFile->hMutex);
mistachkin318507b2011-11-11 22:08:542449 osCloseHandle(pFile->hMutex);
drh72aead82006-01-23 15:54:252450 pFile->hMutex = NULL;
mistachkin7e87eae2013-02-12 09:46:482451 return SQLITE_IOERR;
drh72aead82006-01-23 15:54:252452 }
mistachkin17835a52014-08-06 03:06:012453
drh72aead82006-01-23 15:54:252454 /* Initialize the shared memory if we're supposed to */
mistachkin7e87eae2013-02-12 09:46:482455 if( bInit ){
mistachkin318507b2011-11-11 22:08:542456 memset(pFile->shared, 0, sizeof(winceLock));
drh72aead82006-01-23 15:54:252457 }
2458
2459 winceMutexRelease(pFile->hMutex);
mistachkin7e87eae2013-02-12 09:46:482460 return SQLITE_OK;
drh72aead82006-01-23 15:54:252461}
2462
2463/*
2464** Destroy the part of winFile that deals with wince locks
2465*/
2466static void winceDestroyLock(winFile *pFile){
2467 if (pFile->hMutex){
2468 /* Acquire the mutex */
2469 winceMutexAcquire(pFile->hMutex);
2470
2471 /* The following blocks should probably assert in debug mode, but they
2472 are to cleanup in case any locks remained open */
2473 if (pFile->local.nReaders){
2474 pFile->shared->nReaders --;
2475 }
2476 if (pFile->local.bReserved){
2477 pFile->shared->bReserved = FALSE;
2478 }
2479 if (pFile->local.bPending){
2480 pFile->shared->bPending = FALSE;
2481 }
2482 if (pFile->local.bExclusive){
2483 pFile->shared->bExclusive = FALSE;
2484 }
2485
2486 /* De-reference and close our copy of the shared memory handle */
mistachkin318507b2011-11-11 22:08:542487 osUnmapViewOfFile(pFile->shared);
2488 osCloseHandle(pFile->hShared);
drh72aead82006-01-23 15:54:252489
2490 /* Done with the mutex */
mistachkin17835a52014-08-06 03:06:012491 winceMutexRelease(pFile->hMutex);
mistachkin318507b2011-11-11 22:08:542492 osCloseHandle(pFile->hMutex);
drh72aead82006-01-23 15:54:252493 pFile->hMutex = NULL;
2494 }
2495}
2496
mistachkin17835a52014-08-06 03:06:012497/*
mistachkin318507b2011-11-11 22:08:542498** An implementation of the LockFile() API of Windows for CE
drh72aead82006-01-23 15:54:252499*/
2500static BOOL winceLockFile(
mistachkina7494862012-04-18 05:57:382501 LPHANDLE phFile,
drh72aead82006-01-23 15:54:252502 DWORD dwFileOffsetLow,
2503 DWORD dwFileOffsetHigh,
2504 DWORD nNumberOfBytesToLockLow,
2505 DWORD nNumberOfBytesToLockHigh
2506){
2507 winFile *pFile = HANDLE_TO_WINFILE(phFile);
2508 BOOL bReturn = FALSE;
2509
shane11bb41f2009-09-10 20:23:302510 UNUSED_PARAMETER(dwFileOffsetHigh);
2511 UNUSED_PARAMETER(nNumberOfBytesToLockHigh);
2512
drh72aead82006-01-23 15:54:252513 if (!pFile->hMutex) return TRUE;
2514 winceMutexAcquire(pFile->hMutex);
2515
2516 /* Wanting an exclusive lock? */
shane11bb41f2009-09-10 20:23:302517 if (dwFileOffsetLow == (DWORD)SHARED_FIRST
2518 && nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){
drh72aead82006-01-23 15:54:252519 if (pFile->shared->nReaders == 0 && pFile->shared->bExclusive == 0){
2520 pFile->shared->bExclusive = TRUE;
2521 pFile->local.bExclusive = TRUE;
2522 bReturn = TRUE;
2523 }
2524 }
2525
2526 /* Want a read-only lock? */
shane11bb41f2009-09-10 20:23:302527 else if (dwFileOffsetLow == (DWORD)SHARED_FIRST &&
shane338ea3c2009-08-05 04:08:292528 nNumberOfBytesToLockLow == 1){
drh72aead82006-01-23 15:54:252529 if (pFile->shared->bExclusive == 0){
2530 pFile->local.nReaders ++;
2531 if (pFile->local.nReaders == 1){
2532 pFile->shared->nReaders ++;
2533 }
2534 bReturn = TRUE;
2535 }
2536 }
2537
2538 /* Want a pending lock? */
drh14880522013-03-01 23:24:042539 else if (dwFileOffsetLow == (DWORD)PENDING_BYTE
2540 && nNumberOfBytesToLockLow == 1){
drh72aead82006-01-23 15:54:252541 /* If no pending lock has been acquired, then acquire it */
2542 if (pFile->shared->bPending == 0) {
2543 pFile->shared->bPending = TRUE;
2544 pFile->local.bPending = TRUE;
2545 bReturn = TRUE;
2546 }
2547 }
shane338ea3c2009-08-05 04:08:292548
drh72aead82006-01-23 15:54:252549 /* Want a reserved lock? */
drh14880522013-03-01 23:24:042550 else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE
2551 && nNumberOfBytesToLockLow == 1){
drh72aead82006-01-23 15:54:252552 if (pFile->shared->bReserved == 0) {
2553 pFile->shared->bReserved = TRUE;
2554 pFile->local.bReserved = TRUE;
2555 bReturn = TRUE;
2556 }
2557 }
2558
2559 winceMutexRelease(pFile->hMutex);
2560 return bReturn;
2561}
2562
2563/*
mistachkin318507b2011-11-11 22:08:542564** An implementation of the UnlockFile API of Windows for CE
drh72aead82006-01-23 15:54:252565*/
2566static BOOL winceUnlockFile(
mistachkina7494862012-04-18 05:57:382567 LPHANDLE phFile,
drh72aead82006-01-23 15:54:252568 DWORD dwFileOffsetLow,
2569 DWORD dwFileOffsetHigh,
2570 DWORD nNumberOfBytesToUnlockLow,
2571 DWORD nNumberOfBytesToUnlockHigh
2572){
2573 winFile *pFile = HANDLE_TO_WINFILE(phFile);
2574 BOOL bReturn = FALSE;
2575
shane11bb41f2009-09-10 20:23:302576 UNUSED_PARAMETER(dwFileOffsetHigh);
2577 UNUSED_PARAMETER(nNumberOfBytesToUnlockHigh);
2578
drh72aead82006-01-23 15:54:252579 if (!pFile->hMutex) return TRUE;
2580 winceMutexAcquire(pFile->hMutex);
2581
2582 /* Releasing a reader lock or an exclusive lock */
shane11bb41f2009-09-10 20:23:302583 if (dwFileOffsetLow == (DWORD)SHARED_FIRST){
drh72aead82006-01-23 15:54:252584 /* Did we have an exclusive lock? */
2585 if (pFile->local.bExclusive){
shane11bb41f2009-09-10 20:23:302586 assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE);
drh72aead82006-01-23 15:54:252587 pFile->local.bExclusive = FALSE;
2588 pFile->shared->bExclusive = FALSE;
2589 bReturn = TRUE;
2590 }
2591
2592 /* Did we just have a reader lock? */
2593 else if (pFile->local.nReaders){
drh14880522013-03-01 23:24:042594 assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE
2595 || nNumberOfBytesToUnlockLow == 1);
drh72aead82006-01-23 15:54:252596 pFile->local.nReaders --;
2597 if (pFile->local.nReaders == 0)
2598 {
2599 pFile->shared->nReaders --;
2600 }
2601 bReturn = TRUE;
2602 }
2603 }
2604
2605 /* Releasing a pending lock */
drh14880522013-03-01 23:24:042606 else if (dwFileOffsetLow == (DWORD)PENDING_BYTE
2607 && nNumberOfBytesToUnlockLow == 1){
drh72aead82006-01-23 15:54:252608 if (pFile->local.bPending){
2609 pFile->local.bPending = FALSE;
2610 pFile->shared->bPending = FALSE;
2611 bReturn = TRUE;
2612 }
2613 }
2614 /* Releasing a reserved lock */
drh14880522013-03-01 23:24:042615 else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE
2616 && nNumberOfBytesToUnlockLow == 1){
drh72aead82006-01-23 15:54:252617 if (pFile->local.bReserved) {
2618 pFile->local.bReserved = FALSE;
2619 pFile->shared->bReserved = FALSE;
2620 bReturn = TRUE;
2621 }
2622 }
2623
2624 winceMutexRelease(pFile->hMutex);
2625 return bReturn;
2626}
drh72aead82006-01-23 15:54:252627/*
2628** End of the special code for wince
2629*****************************************************************************/
danielk197729bafea2008-06-26 10:41:192630#endif /* SQLITE_OS_WINCE */
drhc0929982005-09-05 19:08:292631
mistachkina7494862012-04-18 05:57:382632/*
2633** Lock a file region.
2634*/
2635static BOOL winLockFile(
2636 LPHANDLE phFile,
2637 DWORD flags,
2638 DWORD offsetLow,
2639 DWORD offsetHigh,
2640 DWORD numBytesLow,
2641 DWORD numBytesHigh
2642){
2643#if SQLITE_OS_WINCE
2644 /*
2645 ** NOTE: Windows CE is handled differently here due its lack of the Win32
2646 ** API LockFile.
2647 */
2648 return winceLockFile(phFile, offsetLow, offsetHigh,
2649 numBytesLow, numBytesHigh);
2650#else
mistachkinb324bc72013-08-28 02:37:292651 if( osIsNT() ){
mistachkina7494862012-04-18 05:57:382652 OVERLAPPED ovlp;
2653 memset(&ovlp, 0, sizeof(OVERLAPPED));
2654 ovlp.Offset = offsetLow;
2655 ovlp.OffsetHigh = offsetHigh;
2656 return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp);
stephan42e5ceb2025-03-10 15:15:132657#ifdef SQLITE_WIN32_HAS_ANSI
mistachkina7494862012-04-18 05:57:382658 }else{
2659 return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
2660 numBytesHigh);
stephan42e5ceb2025-03-10 15:15:132661#endif
mistachkina7494862012-04-18 05:57:382662 }
2663#endif
2664}
2665
2666/*
dana1801312024-11-30 20:00:542667** Lock a region of nByte bytes starting at offset offset of file hFile.
dan6bd3faa2024-11-22 21:24:082668** Take an EXCLUSIVE lock if parameter bExclusive is true, or a SHARED lock
2669** otherwise. If nMs is greater than zero and the lock cannot be obtained
2670** immediately, block for that many ms before giving up.
2671**
dan6bd3faa2024-11-22 21:24:082672** This function returns SQLITE_OK if the lock is obtained successfully. If
2673** some other process holds the lock, SQLITE_BUSY is returned if nMs==0, or
2674** SQLITE_BUSY_TIMEOUT otherwise. Or, if an error occurs, SQLITE_IOERR.
2675*/
dand50eb9c2024-12-10 19:00:072676static int winHandleLockTimeout(
dan1743c5f2024-11-25 16:54:102677 HANDLE hFile,
dan6bd3faa2024-11-22 21:24:082678 DWORD offset,
2679 DWORD nByte,
2680 int bExcl,
dan46288882025-01-30 15:26:162681 DWORD nMs
dan6bd3faa2024-11-22 21:24:082682){
2683 DWORD flags = LOCKFILE_FAIL_IMMEDIATELY | (bExcl?LOCKFILE_EXCLUSIVE_LOCK:0);
2684 int rc = SQLITE_OK;
2685 BOOL ret;
2686
dan6bd3faa2024-11-22 21:24:082687 if( !osIsNT() ){
dan1743c5f2024-11-25 16:54:102688 ret = winLockFile(&hFile, flags, offset, 0, nByte, 0);
dan6bd3faa2024-11-22 21:24:082689 }else{
2690 OVERLAPPED ovlp;
2691 memset(&ovlp, 0, sizeof(OVERLAPPED));
2692 ovlp.Offset = offset;
dan1743c5f2024-11-25 16:54:102693
dance502822024-12-24 14:44:382694#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
dan46288882025-01-30 15:26:162695 if( nMs!=0 ){
dan1743c5f2024-11-25 16:54:102696 flags &= ~LOCKFILE_FAIL_IMMEDIATELY;
dan6bd3faa2024-11-22 21:24:082697 }
dance502822024-12-24 14:44:382698 ovlp.hEvent = osCreateEvent(NULL, TRUE, FALSE, NULL);
2699 if( ovlp.hEvent==NULL ){
2700 return SQLITE_IOERR_LOCK;
2701 }
2702#endif
dan6bd3faa2024-11-22 21:24:082703
dan1743c5f2024-11-25 16:54:102704 ret = osLockFileEx(hFile, flags, 0, nByte, 0, &ovlp);
danf6d26742024-11-25 18:47:122705
dance502822024-12-24 14:44:382706#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
2707 /* If SQLITE_ENABLE_SETLK_TIMEOUT is defined, then the file-handle was
2708 ** opened with FILE_FLAG_OVERHEAD specified. In this case, the call to
2709 ** LockFileEx() may fail because the request is still pending. This can
dan46288882025-01-30 15:26:162710 ** happen even if LOCKFILE_FAIL_IMMEDIATELY was specified.
2711 **
2712 ** If nMs is 0, then LOCKFILE_FAIL_IMMEDIATELY was set in the flags
2713 ** passed to LockFileEx(). In this case, if the operation is pending,
2714 ** block indefinitely until it is finished.
2715 **
2716 ** Otherwise, wait for up to nMs ms for the operation to finish. nMs
2717 ** may be set to INFINITE.
2718 */
dance502822024-12-24 14:44:382719 if( !ret && GetLastError()==ERROR_IO_PENDING ){
dan46288882025-01-30 15:26:162720 DWORD nDelay = (nMs==0 ? INFINITE : nMs);
dance502822024-12-24 14:44:382721 DWORD res = osWaitForSingleObject(ovlp.hEvent, nDelay);
dan1743c5f2024-11-25 16:54:102722 if( res==WAIT_OBJECT_0 ){
dan1743c5f2024-11-25 16:54:102723 ret = TRUE;
dance502822024-12-24 14:44:382724 }else if( res==WAIT_TIMEOUT ){
dan69ce7582025-06-02 18:37:322725#if SQLITE_ENABLE_SETLK_TIMEOUT==1
dance502822024-12-24 14:44:382726 rc = SQLITE_BUSY_TIMEOUT;
dan69ce7582025-06-02 18:37:322727#else
2728 rc = SQLITE_BUSY;
2729#endif
dan1743c5f2024-11-25 16:54:102730 }else{
dance502822024-12-24 14:44:382731 /* Some other error has occurred */
2732 rc = SQLITE_IOERR_LOCK;
dan6bd3faa2024-11-22 21:24:082733 }
dan362d51a2024-12-26 16:10:152734
2735 /* If it is still pending, cancel the LockFileEx() call. */
dance502822024-12-24 14:44:382736 osCancelIo(hFile);
dan1743c5f2024-11-25 16:54:102737 }
2738
dance502822024-12-24 14:44:382739 osCloseHandle(ovlp.hEvent);
2740#endif
dan6bd3faa2024-11-22 21:24:082741 }
dan6bd3faa2024-11-22 21:24:082742
2743 if( rc==SQLITE_OK && !ret ){
2744 rc = SQLITE_BUSY;
2745 }
2746 return rc;
2747}
2748
2749/*
mistachkina7494862012-04-18 05:57:382750** Unlock a file region.
2751 */
2752static BOOL winUnlockFile(
2753 LPHANDLE phFile,
2754 DWORD offsetLow,
2755 DWORD offsetHigh,
2756 DWORD numBytesLow,
2757 DWORD numBytesHigh
2758){
2759#if SQLITE_OS_WINCE
2760 /*
2761 ** NOTE: Windows CE is handled differently here due its lack of the Win32
2762 ** API UnlockFile.
2763 */
2764 return winceUnlockFile(phFile, offsetLow, offsetHigh,
2765 numBytesLow, numBytesHigh);
2766#else
mistachkinb324bc72013-08-28 02:37:292767 if( osIsNT() ){
mistachkina7494862012-04-18 05:57:382768 OVERLAPPED ovlp;
2769 memset(&ovlp, 0, sizeof(OVERLAPPED));
2770 ovlp.Offset = offsetLow;
2771 ovlp.OffsetHigh = offsetHigh;
2772 return osUnlockFileEx(*phFile, 0, numBytesLow, numBytesHigh, &ovlp);
stephan42e5ceb2025-03-10 15:15:132773#ifdef SQLITE_WIN32_HAS_ANSI
mistachkina7494862012-04-18 05:57:382774 }else{
2775 return osUnlockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
2776 numBytesHigh);
stephan42e5ceb2025-03-10 15:15:132777#endif
mistachkina7494862012-04-18 05:57:382778 }
2779#endif
2780}
2781
dand50eb9c2024-12-10 19:00:072782/*
2783** Remove an nByte lock starting at offset iOff from HANDLE h.
2784*/
dana1801312024-11-30 20:00:542785static int winHandleUnlock(HANDLE h, int iOff, int nByte){
2786 BOOL ret = winUnlockFile(&h, iOff, 0, nByte, 0);
2787 return (ret ? SQLITE_OK : SQLITE_IOERR_UNLOCK);
2788}
2789
drh153c62c2007-08-24 03:51:332790/*****************************************************************************
2791** The next group of routines implement the I/O methods specified
2792** by the sqlite3_io_methods object.
2793******************************************************************************/
drhbbd42a62004-05-22 17:41:582794
2795/*
mistachkin318507b2011-11-11 22:08:542796** Some Microsoft compilers lack this definition.
dan502019c2010-07-28 14:26:172797*/
2798#ifndef INVALID_SET_FILE_POINTER
2799# define INVALID_SET_FILE_POINTER ((DWORD)-1)
2800#endif
2801
2802/*
dana1801312024-11-30 20:00:542803** Seek the file handle h to offset nByte of the file.
2804**
2805** If successful, return SQLITE_OK. Or, if an error occurs, return an SQLite
2806** error code.
dan502019c2010-07-28 14:26:172807*/
dana1801312024-11-30 20:00:542808static int winHandleSeek(HANDLE h, sqlite3_int64 iOffset){
2809 int rc = SQLITE_OK; /* Return value */
2810
mistachkindf562d52012-03-13 01:16:572811#if !SQLITE_OS_WINRT
dan502019c2010-07-28 14:26:172812 LONG upperBits; /* Most sig. 32 bits of new offset */
2813 LONG lowerBits; /* Least sig. 32 bits of new offset */
2814 DWORD dwRet; /* Value returned by SetFilePointer() */
mistachkinf2c1c992013-04-28 01:44:432815
dan502019c2010-07-28 14:26:172816 upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
2817 lowerBits = (LONG)(iOffset & 0xffffffff);
2818
dana1801312024-11-30 20:00:542819 dwRet = osSetFilePointer(h, lowerBits, &upperBits, FILE_BEGIN);
2820
mistachkin17835a52014-08-06 03:06:012821 /* API oddity: If successful, SetFilePointer() returns a dword
dan502019c2010-07-28 14:26:172822 ** containing the lower 32-bits of the new file-offset. Or, if it fails,
mistachkin17835a52014-08-06 03:06:012823 ** it returns INVALID_SET_FILE_POINTER. However according to MSDN,
2824 ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine
2825 ** whether an error has actually occurred, it is also necessary to call
dana1801312024-11-30 20:00:542826 ** GetLastError(). */
2827 if( dwRet==INVALID_SET_FILE_POINTER ){
2828 DWORD lastErrno = osGetLastError();
2829 if( lastErrno!=NO_ERROR ){
2830 rc = SQLITE_IOERR_SEEK;
2831 }
dan502019c2010-07-28 14:26:172832 }
mistachkindf562d52012-03-13 01:16:572833#else
dana1801312024-11-30 20:00:542834 /* This implementation works for WinRT. */
mistachkin75b70a22012-03-02 13:47:162835 LARGE_INTEGER x; /* The new offset */
2836 BOOL bRet; /* Value returned by SetFilePointerEx() */
2837
drh8045df02012-03-01 22:06:302838 x.QuadPart = iOffset;
dana1801312024-11-30 20:00:542839 bRet = osSetFilePointerEx(h, x, 0, FILE_BEGIN);
mistachkin75b70a22012-03-02 13:47:162840
2841 if(!bRet){
dana1801312024-11-30 20:00:542842 rc = SQLITE_IOERR_SEEK;
mistachkin75b70a22012-03-02 13:47:162843 }
drh8045df02012-03-01 22:06:302844#endif
dana1801312024-11-30 20:00:542845
2846 OSTRACE(("SEEK file=%p, offset=%lld rc=%s\n", h, iOffset, sqlite3ErrName(rc)));
2847 return rc;
mistachkindf562d52012-03-13 01:16:572848}
dan502019c2010-07-28 14:26:172849
dana1801312024-11-30 20:00:542850/*
2851** Move the current position of the file handle passed as the first
2852** argument to offset iOffset within the file. If successful, return 0.
2853** Otherwise, set pFile->lastErrno and return non-zero.
2854*/
2855static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){
2856 int rc;
2857
2858 rc = winHandleSeek(pFile->h, iOffset);
2859 if( rc!=SQLITE_OK ){
2860 pFile->lastErrno = osGetLastError();
2861 winLogError(rc, pFile->lastErrno, "winSeekFile", pFile->zPath);
2862 }
2863 return rc;
2864}
2865
2866
mistachkin5824e052013-04-15 20:08:272867#if SQLITE_MAX_MMAP_SIZE>0
mistachkind95a3d32013-08-30 21:52:382868/* Forward references to VFS helper methods used for memory mapped files */
2869static int winMapfile(winFile*, sqlite3_int64);
drh5175b322013-04-01 17:22:512870static int winUnmapfile(winFile*);
mistachkin5824e052013-04-15 20:08:272871#endif
mistachkindaf9a5a2013-03-23 09:56:392872
dan502019c2010-07-28 14:26:172873/*
drhbbd42a62004-05-22 17:41:582874** Close a file.
drh59e63a62006-06-04 23:31:482875**
2876** It is reported that an attempt to close a handle might sometimes
mistachkin318507b2011-11-11 22:08:542877** fail. This is a very unreasonable result, but Windows is notorious
drh59e63a62006-06-04 23:31:482878** for being unreasonable so I do not doubt that it might happen. If
2879** the close fails, we pause for 100 milliseconds and try again. As
2880** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before
2881** giving up and returning an error.
drhbbd42a62004-05-22 17:41:582882*/
drh59e63a62006-06-04 23:31:482883#define MX_CLOSE_ATTEMPT 3
drh153c62c2007-08-24 03:51:332884static int winClose(sqlite3_file *id){
2885 int rc, cnt = 0;
2886 winFile *pFile = (winFile*)id;
shane50daafc2009-03-05 05:54:552887
2888 assert( id!=0 );
mistachkin6f928332012-08-17 11:47:322889#ifndef SQLITE_OMIT_WAL
drh83235212010-05-14 16:34:342890 assert( pFile->pShm==0 );
mistachkin6f928332012-08-17 11:47:322891#endif
mistachkin9ce59a92013-02-13 22:54:032892 assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE );
mistachkinad1e55e2015-03-27 18:20:252893 OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p\n",
2894 osGetCurrentProcessId(), pFile, pFile->h));
mistachkindaf9a5a2013-03-23 09:56:392895
mistachkin5824e052013-04-15 20:08:272896#if SQLITE_MAX_MMAP_SIZE>0
mistachkinc2165662013-10-16 09:49:102897 winUnmapfile(pFile);
mistachkin5824e052013-04-15 20:08:272898#endif
mistachkindaf9a5a2013-03-23 09:56:392899
drh153c62c2007-08-24 03:51:332900 do{
mistachkin318507b2011-11-11 22:08:542901 rc = osCloseHandle(pFile->h);
shanehe2ad9312010-07-08 03:13:332902 /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */
mistachkinf4f327c2012-03-13 03:35:072903 }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) );
danielk197729bafea2008-06-26 10:41:192904#if SQLITE_OS_WINCE
drhd641d512008-02-20 00:00:002905#define WINCE_DELETION_ATTEMPTS 3
mistachkin1e754832016-07-08 21:14:372906 {
2907 winVfsAppData *pAppData = (winVfsAppData*)pFile->pVfs->pAppData;
2908 if( pAppData==NULL || !pAppData->bNoLock ){
2909 winceDestroyLock(pFile);
2910 }
2911 }
drh7229ed42007-10-08 12:29:172912 if( pFile->zDeleteOnClose ){
drhd641d512008-02-20 00:00:002913 int cnt = 0;
2914 while(
mistachkin318507b2011-11-11 22:08:542915 osDeleteFileW(pFile->zDeleteOnClose)==0
mistachkin17835a52014-08-06 03:06:012916 && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff
drhd641d512008-02-20 00:00:002917 && cnt++ < WINCE_DELETION_ATTEMPTS
2918 ){
mistachkinf4f327c2012-03-13 03:35:072919 sqlite3_win32_sleep(100); /* Wait a little before trying again */
drhd641d512008-02-20 00:00:002920 }
mistachkin5f075382011-11-11 23:31:042921 sqlite3_free(pFile->zDeleteOnClose);
drh7229ed42007-10-08 12:29:172922 }
drhcc78fea2006-01-06 16:17:052923#endif
mistachkin05340e32012-03-30 12:27:552924 if( rc ){
2925 pFile->h = NULL;
2926 }
drh153c62c2007-08-24 03:51:332927 OpenCounter(-1);
mistachkinad1e55e2015-03-27 18:20:252928 OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p, rc=%s\n",
2929 osGetCurrentProcessId(), pFile, pFile->h, rc ? "ok" : "failed"));
drh50990db2011-04-13 20:26:132930 return rc ? SQLITE_OK
mistachkin318507b2011-11-11 22:08:542931 : winLogError(SQLITE_IOERR_CLOSE, osGetLastError(),
mistachkin2aef9972011-11-10 20:21:202932 "winClose", pFile->zPath);
drhbbd42a62004-05-22 17:41:582933}
2934
2935/*
2936** Read data from a file into a buffer. Return SQLITE_OK if all
2937** bytes were read successfully and SQLITE_IOERR if anything goes
2938** wrong.
2939*/
drh153c62c2007-08-24 03:51:332940static int winRead(
2941 sqlite3_file *id, /* File to read from */
2942 void *pBuf, /* Write content into this buffer */
2943 int amt, /* Number of bytes to read */
2944 sqlite3_int64 offset /* Begin reading at this offset */
2945){
mistachkind9d812f2014-12-20 22:21:492946#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
mistachkin05340e32012-03-30 12:27:552947 OVERLAPPED overlapped; /* The offset for ReadFile. */
mistachkin00fa55d2012-03-30 16:44:332948#endif
dan502019c2010-07-28 14:26:172949 winFile *pFile = (winFile*)id; /* file handle */
2950 DWORD nRead; /* Number of bytes actually read from file */
drh5d9ef0a2011-07-11 18:17:562951 int nRetry = 0; /* Number of retrys */
shane50daafc2009-03-05 05:54:552952
drh9cbe6352005-11-29 03:13:212953 assert( id!=0 );
mistachkindaf9a5a2013-03-23 09:56:392954 assert( amt>0 );
drh6cf9d8d2013-05-09 18:12:402955 assert( offset>=0 );
drh9cce7102007-01-09 17:18:192956 SimulateIOError(return SQLITE_IOERR_READ);
mistachkinad1e55e2015-03-27 18:20:252957 OSTRACE(("READ pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, "
2958 "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile,
mistachkinf2c1c992013-04-28 01:44:432959 pFile->h, pBuf, amt, offset, pFile->locktype));
dan502019c2010-07-28 14:26:172960
drh9b4c59f2013-04-15 17:03:422961#if SQLITE_MAX_MMAP_SIZE>0
larrybrbc917382023-06-07 08:40:312962 /* Deal with as much of this read request as possible by transferring
drh5175b322013-04-01 17:22:512963 ** data from the memory mapping using memcpy(). */
2964 if( offset<pFile->mmapSize ){
2965 if( offset+amt <= pFile->mmapSize ){
2966 memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt);
mistachkinad1e55e2015-03-27 18:20:252967 OSTRACE(("READ-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
2968 osGetCurrentProcessId(), pFile, pFile->h));
drh5175b322013-04-01 17:22:512969 return SQLITE_OK;
2970 }else{
2971 int nCopy = (int)(pFile->mmapSize - offset);
2972 memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy);
2973 pBuf = &((u8 *)pBuf)[nCopy];
2974 amt -= nCopy;
2975 offset += nCopy;
2976 }
2977 }
drh6e0b6d52013-04-09 16:19:202978#endif
dan502019c2010-07-28 14:26:172979
mistachkind9d812f2014-12-20 22:21:492980#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
mistachkinb324bc72013-08-28 02:37:292981 if( winSeekFile(pFile, offset) ){
mistachkinad1e55e2015-03-27 18:20:252982 OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n",
2983 osGetCurrentProcessId(), pFile, pFile->h));
mistachkin00fa55d2012-03-30 16:44:332984 return SQLITE_FULL;
2985 }
2986 while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
2987#else
mistachkin05340e32012-03-30 12:27:552988 memset(&overlapped, 0, sizeof(OVERLAPPED));
2989 overlapped.Offset = (LONG)(offset & 0xffffffff);
2990 overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
2991 while( !osReadFile(pFile->h, pBuf, amt, &nRead, &overlapped) &&
2992 osGetLastError()!=ERROR_HANDLE_EOF ){
mistachkin00fa55d2012-03-30 16:44:332993#endif
mistachkind1ef9b62011-11-21 00:54:372994 DWORD lastErrno;
mistachkinb324bc72013-08-28 02:37:292995 if( winRetryIoerr(&nRetry, &lastErrno) ) continue;
mistachkind1ef9b62011-11-21 00:54:372996 pFile->lastErrno = lastErrno;
mistachkinad1e55e2015-03-27 18:20:252997 OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_READ\n",
2998 osGetCurrentProcessId(), pFile, pFile->h));
mistachkin2aef9972011-11-10 20:21:202999 return winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
mistachkin9f11ef12013-08-31 02:48:563000 "winRead", pFile->zPath);
drhbbd42a62004-05-22 17:41:583001 }
drh21aa6a12015-03-26 15:27:323002 winLogIoerr(nRetry, __LINE__);
dan502019c2010-07-28 14:26:173003 if( nRead<(DWORD)amt ){
drh4c17c3f2008-11-07 00:06:183004 /* Unread parts of the buffer must be zero-filled */
dan502019c2010-07-28 14:26:173005 memset(&((char*)pBuf)[nRead], 0, amt-nRead);
mistachkinad1e55e2015-03-27 18:20:253006 OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_SHORT_READ\n",
3007 osGetCurrentProcessId(), pFile, pFile->h));
drh551b7732006-11-06 21:20:253008 return SQLITE_IOERR_SHORT_READ;
drhbbd42a62004-05-22 17:41:583009 }
dan502019c2010-07-28 14:26:173010
mistachkinad1e55e2015-03-27 18:20:253011 OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
3012 osGetCurrentProcessId(), pFile, pFile->h));
dan502019c2010-07-28 14:26:173013 return SQLITE_OK;
drhbbd42a62004-05-22 17:41:583014}
3015
3016/*
3017** Write data from a buffer into a file. Return SQLITE_OK on success
3018** or some other error code on failure.
3019*/
drh153c62c2007-08-24 03:51:333020static int winWrite(
dan502019c2010-07-28 14:26:173021 sqlite3_file *id, /* File to write into */
3022 const void *pBuf, /* The bytes to be written */
3023 int amt, /* Number of bytes to write */
3024 sqlite3_int64 offset /* Offset into the file to begin writing at */
drh153c62c2007-08-24 03:51:333025){
mistachkin48864df2013-03-21 21:20:323026 int rc = 0; /* True if error has occurred, else false */
dan502019c2010-07-28 14:26:173027 winFile *pFile = (winFile*)id; /* File handle */
drha32ad842011-07-12 13:51:053028 int nRetry = 0; /* Number of retries */
shane50daafc2009-03-05 05:54:553029
dan502019c2010-07-28 14:26:173030 assert( amt>0 );
3031 assert( pFile );
drh153c62c2007-08-24 03:51:333032 SimulateIOError(return SQLITE_IOERR_WRITE);
drh59685932006-09-14 13:47:113033 SimulateDiskfullError(return SQLITE_FULL);
dan502019c2010-07-28 14:26:173034
mistachkinad1e55e2015-03-27 18:20:253035 OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, "
3036 "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile,
mistachkinf2c1c992013-04-28 01:44:433037 pFile->h, pBuf, amt, offset, pFile->locktype));
dan502019c2010-07-28 14:26:173038
mistachkinc88cd132015-11-17 21:42:323039#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0
larrybrbc917382023-06-07 08:40:313040 /* Deal with as much of this write request as possible by transferring
drh5175b322013-04-01 17:22:513041 ** data from the memory mapping using memcpy(). */
3042 if( offset<pFile->mmapSize ){
3043 if( offset+amt <= pFile->mmapSize ){
3044 memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt);
mistachkinad1e55e2015-03-27 18:20:253045 OSTRACE(("WRITE-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
3046 osGetCurrentProcessId(), pFile, pFile->h));
drh5175b322013-04-01 17:22:513047 return SQLITE_OK;
3048 }else{
3049 int nCopy = (int)(pFile->mmapSize - offset);
3050 memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy);
3051 pBuf = &((u8 *)pBuf)[nCopy];
3052 amt -= nCopy;
3053 offset += nCopy;
3054 }
3055 }
drh6e0b6d52013-04-09 16:19:203056#endif
dan502019c2010-07-28 14:26:173057
mistachkind9d812f2014-12-20 22:21:493058#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
mistachkinb324bc72013-08-28 02:37:293059 rc = winSeekFile(pFile, offset);
mistachkin00fa55d2012-03-30 16:44:333060 if( rc==0 ){
3061#else
mistachkin05340e32012-03-30 12:27:553062 {
mistachkin00fa55d2012-03-30 16:44:333063#endif
mistachkind9d812f2014-12-20 22:21:493064#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
mistachkin05340e32012-03-30 12:27:553065 OVERLAPPED overlapped; /* The offset for WriteFile. */
mistachkin00fa55d2012-03-30 16:44:333066#endif
dan502019c2010-07-28 14:26:173067 u8 *aRem = (u8 *)pBuf; /* Data yet to be written */
3068 int nRem = amt; /* Number of bytes yet to be written */
3069 DWORD nWrite; /* Bytes written by each WriteFile() call */
mistachkind1ef9b62011-11-21 00:54:373070 DWORD lastErrno = NO_ERROR; /* Value returned by GetLastError() */
dan502019c2010-07-28 14:26:173071
mistachkind9d812f2014-12-20 22:21:493072#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
mistachkin05340e32012-03-30 12:27:553073 memset(&overlapped, 0, sizeof(OVERLAPPED));
3074 overlapped.Offset = (LONG)(offset & 0xffffffff);
3075 overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
mistachkin00fa55d2012-03-30 16:44:333076#endif
mistachkin05340e32012-03-30 12:27:553077
drh5d9ef0a2011-07-11 18:17:563078 while( nRem>0 ){
mistachkind9d812f2014-12-20 22:21:493079#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
mistachkin00fa55d2012-03-30 16:44:333080 if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
3081#else
mistachkin05340e32012-03-30 12:27:553082 if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){
mistachkin00fa55d2012-03-30 16:44:333083#endif
mistachkinb324bc72013-08-28 02:37:293084 if( winRetryIoerr(&nRetry, &lastErrno) ) continue;
drh5d9ef0a2011-07-11 18:17:563085 break;
3086 }
mistachkine1b461b2012-10-18 09:39:163087 assert( nWrite==0 || nWrite<=(DWORD)nRem );
3088 if( nWrite==0 || nWrite>(DWORD)nRem ){
mistachkin05340e32012-03-30 12:27:553089 lastErrno = osGetLastError();
3090 break;
3091 }
mistachkind9d812f2014-12-20 22:21:493092#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
mistachkin05340e32012-03-30 12:27:553093 offset += nWrite;
3094 overlapped.Offset = (LONG)(offset & 0xffffffff);
3095 overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
mistachkin00fa55d2012-03-30 16:44:333096#endif
dan502019c2010-07-28 14:26:173097 aRem += nWrite;
3098 nRem -= nWrite;
3099 }
3100 if( nRem>0 ){
mistachkind1ef9b62011-11-21 00:54:373101 pFile->lastErrno = lastErrno;
dan502019c2010-07-28 14:26:173102 rc = 1;
shaneh133ce562010-07-06 20:33:473103 }
drh153c62c2007-08-24 03:51:333104 }
dan502019c2010-07-28 14:26:173105
3106 if( rc ){
shaneheeb5d8a2011-06-20 20:48:093107 if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL )
3108 || ( pFile->lastErrno==ERROR_DISK_FULL )){
mistachkinad1e55e2015-03-27 18:20:253109 OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n",
3110 osGetCurrentProcessId(), pFile, pFile->h));
mistachkin9f11ef12013-08-31 02:48:563111 return winLogError(SQLITE_FULL, pFile->lastErrno,
3112 "winWrite1", pFile->zPath);
shaneh133ce562010-07-06 20:33:473113 }
mistachkinad1e55e2015-03-27 18:20:253114 OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_WRITE\n",
3115 osGetCurrentProcessId(), pFile, pFile->h));
mistachkin2aef9972011-11-10 20:21:203116 return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno,
mistachkin9f11ef12013-08-31 02:48:563117 "winWrite2", pFile->zPath);
drha32ad842011-07-12 13:51:053118 }else{
drh21aa6a12015-03-26 15:27:323119 winLogIoerr(nRetry, __LINE__);
drhbbd42a62004-05-22 17:41:583120 }
mistachkinad1e55e2015-03-27 18:20:253121 OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
3122 osGetCurrentProcessId(), pFile, pFile->h));
drhbbd42a62004-05-22 17:41:583123 return SQLITE_OK;
3124}
3125
3126/*
dana1801312024-11-30 20:00:543127** Truncate the file opened by handle h to nByte bytes in size.
3128*/
3129static int winHandleTruncate(HANDLE h, sqlite3_int64 nByte){
3130 int rc = SQLITE_OK; /* Return code */
3131 rc = winHandleSeek(h, nByte);
3132 if( rc==SQLITE_OK ){
3133 if( 0==osSetEndOfFile(h) ){
3134 rc = SQLITE_IOERR_TRUNCATE;
3135 }
3136 }
3137 return rc;
3138}
3139
3140/*
3141** Determine the size in bytes of the file opened by the handle passed as
3142** the first argument.
3143*/
3144static int winHandleSize(HANDLE h, sqlite3_int64 *pnByte){
3145 int rc = SQLITE_OK;
3146
3147#if SQLITE_OS_WINRT
3148 FILE_STANDARD_INFO info;
3149 BOOL b;
3150 b = osGetFileInformationByHandleEx(h, FileStandardInfo, &info, sizeof(info));
3151 if( b ){
3152 *pnByte = info.EndOfFile.QuadPart;
3153 }else{
3154 rc = SQLITE_IOERR_FSTAT;
3155 }
3156#else
3157 DWORD upperBits = 0;
3158 DWORD lowerBits = 0;
dana1801312024-11-30 20:00:543159
dance502822024-12-24 14:44:383160 assert( pnByte );
dana1801312024-11-30 20:00:543161 lowerBits = osGetFileSize(h, &upperBits);
3162 *pnByte = (((sqlite3_int64)upperBits)<<32) + lowerBits;
dana1801312024-11-30 20:00:543163 if( lowerBits==INVALID_FILE_SIZE && osGetLastError()!=NO_ERROR ){
3164 rc = SQLITE_IOERR_FSTAT;
3165 }
3166#endif
3167
3168 return rc;
3169}
3170
3171/*
dance502822024-12-24 14:44:383172** Close the handle passed as the only argument.
3173*/
3174static void winHandleClose(HANDLE h){
3175 if( h!=INVALID_HANDLE_VALUE ){
3176 osCloseHandle(h);
3177 }
3178}
3179
3180/*
drh153c62c2007-08-24 03:51:333181** Truncate an open file to a specified size
drhbbdc2b92005-09-19 12:53:183182*/
drhc51250a2007-09-20 14:39:233183static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
dan502019c2010-07-28 14:26:173184 winFile *pFile = (winFile*)id; /* File handle object */
3185 int rc = SQLITE_OK; /* Return code for this function */
mistachkindaf9a5a2013-03-23 09:56:393186 DWORD lastErrno;
mistachkin1e8487d2018-07-22 06:25:353187#if SQLITE_MAX_MMAP_SIZE>0
3188 sqlite3_int64 oldMmapSize;
drheafb9a02018-11-24 17:46:073189 if( pFile->nFetchOut>0 ){
3190 /* File truncation is a no-op if there are outstanding memory mapped
3191 ** pages. This is because truncating the file means temporarily unmapping
3192 ** the file, and that might delete memory out from under existing cursors.
3193 **
3194 ** This can result in incremental vacuum not truncating the file,
3195 ** if there is an active read cursor when the incremental vacuum occurs.
3196 ** No real harm comes of this - the database file is not corrupted,
3197 ** though some folks might complain that the file is bigger than it
3198 ** needs to be.
3199 **
3200 ** The only feasible work-around is to defer the truncation until after
3201 ** all references to memory-mapped content are closed. That is doable,
3202 ** but involves adding a few branches in the common write code path which
3203 ** could slow down normal operations slightly. Hence, we have decided for
larrybrbc917382023-06-07 08:40:313204 ** now to simply make transactions a no-op if there are pending reads. We
drheafb9a02018-11-24 17:46:073205 ** can maybe revisit this decision in the future.
3206 */
3207 return SQLITE_OK;
3208 }
mistachkin1e8487d2018-07-22 06:25:353209#endif
shane50daafc2009-03-05 05:54:553210
dan502019c2010-07-28 14:26:173211 assert( pFile );
drh153c62c2007-08-24 03:51:333212 SimulateIOError(return SQLITE_IOERR_TRUNCATE);
mistachkinad1e55e2015-03-27 18:20:253213 OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, size=%lld, lock=%d\n",
3214 osGetCurrentProcessId(), pFile, pFile->h, nByte, pFile->locktype));
dan502019c2010-07-28 14:26:173215
3216 /* If the user has configured a chunk-size for this file, truncate the
3217 ** file so that it consists of an integer number of chunks (i.e. the
3218 ** actual file size after the operation may be larger than the requested
3219 ** size).
3220 */
mistachkind589a542011-08-30 01:23:343221 if( pFile->szChunk>0 ){
dan502019c2010-07-28 14:26:173222 nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
3223 }
3224
mistachkin1e8487d2018-07-22 06:25:353225#if SQLITE_MAX_MMAP_SIZE>0
3226 if( pFile->pMapRegion ){
3227 oldMmapSize = pFile->mmapSize;
3228 }else{
3229 oldMmapSize = 0;
3230 }
3231 winUnmapfile(pFile);
3232#endif
3233
dan502019c2010-07-28 14:26:173234 /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
mistachkinb324bc72013-08-28 02:37:293235 if( winSeekFile(pFile, nByte) ){
mistachkin2aef9972011-11-10 20:21:203236 rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
mistachkindaf9a5a2013-03-23 09:56:393237 "winTruncate1", pFile->zPath);
3238 }else if( 0==osSetEndOfFile(pFile->h) &&
3239 ((lastErrno = osGetLastError())!=ERROR_USER_MAPPED_FILE) ){
3240 pFile->lastErrno = lastErrno;
mistachkin2aef9972011-11-10 20:21:203241 rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
mistachkindaf9a5a2013-03-23 09:56:393242 "winTruncate2", pFile->zPath);
shanea3465f22008-10-12 02:27:383243 }
dan502019c2010-07-28 14:26:173244
drh9b4c59f2013-04-15 17:03:423245#if SQLITE_MAX_MMAP_SIZE>0
mistachkin1e8487d2018-07-22 06:25:353246 if( rc==SQLITE_OK && oldMmapSize>0 ){
3247 if( oldMmapSize>nByte ){
3248 winMapfile(pFile, -1);
3249 }else{
3250 winMapfile(pFile, oldMmapSize);
3251 }
shanea3465f22008-10-12 02:27:383252 }
drh6e0b6d52013-04-09 16:19:203253#endif
dan502019c2010-07-28 14:26:173254
mistachkinad1e55e2015-03-27 18:20:253255 OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, rc=%s\n",
3256 osGetCurrentProcessId(), pFile, pFile->h, sqlite3ErrName(rc)));
shaneh04882a92010-05-11 02:49:393257 return rc;
drhbbd42a62004-05-22 17:41:583258}
3259
drhdec6fae2007-09-03 17:02:503260#ifdef SQLITE_TEST
3261/*
3262** Count the number of fullsyncs and normal syncs. This is used to test
larrybrbc917382023-06-07 08:40:313263** that syncs and fullsyncs are occurring at the right times.
drhdec6fae2007-09-03 17:02:503264*/
3265int sqlite3_sync_count = 0;
3266int sqlite3_fullsync_count = 0;
3267#endif
3268
drhbbd42a62004-05-22 17:41:583269/*
3270** Make sure all writes to a particular file are committed to disk.
3271*/
drh153c62c2007-08-24 03:51:333272static int winSync(sqlite3_file *id, int flags){
mistachkinc377f312011-09-16 20:43:443273#ifndef SQLITE_NO_SYNC
3274 /*
3275 ** Used only when SQLITE_NO_SYNC is not defined.
3276 */
shaneh9dd6e082011-04-15 20:18:403277 BOOL rc;
mistachkinc377f312011-09-16 20:43:443278#endif
3279#if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || \
mistachkinfb383e92015-04-16 03:24:383280 defined(SQLITE_HAVE_OS_TRACE)
mistachkinc377f312011-09-16 20:43:443281 /*
3282 ** Used when SQLITE_NO_SYNC is not defined and by the assert() and/or
3283 ** OSTRACE() macros.
3284 */
3285 winFile *pFile = (winFile*)id;
shane18e526c2008-12-10 22:30:243286#else
3287 UNUSED_PARAMETER(id);
3288#endif
shanehe2ad9312010-07-08 03:13:333289
3290 assert( pFile );
3291 /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */
3292 assert((flags&0x0F)==SQLITE_SYNC_NORMAL
3293 || (flags&0x0F)==SQLITE_SYNC_FULL
3294 );
3295
shanehe2ad9312010-07-08 03:13:333296 /* Unix cannot, but some systems may return SQLITE_FULL from here. This
3297 ** line is to test that doing so does not cause any problems.
3298 */
3299 SimulateDiskfullError( return SQLITE_FULL );
shaneh9dd6e082011-04-15 20:18:403300
mistachkinad1e55e2015-03-27 18:20:253301 OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, flags=%x, lock=%d\n",
3302 osGetCurrentProcessId(), pFile, pFile->h, flags,
3303 pFile->locktype));
mistachkinf2c1c992013-04-28 01:44:433304
shaneh9dd6e082011-04-15 20:18:403305#ifndef SQLITE_TEST
3306 UNUSED_PARAMETER(flags);
3307#else
3308 if( (flags&0x0F)==SQLITE_SYNC_FULL ){
3309 sqlite3_fullsync_count++;
3310 }
3311 sqlite3_sync_count++;
3312#endif
shanehe2ad9312010-07-08 03:13:333313
shane84ca3832008-11-13 18:20:433314 /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
3315 ** no-op
3316 */
3317#ifdef SQLITE_NO_SYNC
mistachkinad1e55e2015-03-27 18:20:253318 OSTRACE(("SYNC-NOP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
3319 osGetCurrentProcessId(), pFile, pFile->h));
shanehe2ad9312010-07-08 03:13:333320 return SQLITE_OK;
shane84ca3832008-11-13 18:20:433321#else
mistachkinccb43712015-03-26 23:36:353322#if SQLITE_MAX_MMAP_SIZE>0
3323 if( pFile->pMapRegion ){
3324 if( osFlushViewOfFile(pFile->pMapRegion, 0) ){
3325 OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, "
3326 "rc=SQLITE_OK\n", osGetCurrentProcessId(),
3327 pFile, pFile->pMapRegion));
3328 }else{
3329 pFile->lastErrno = osGetLastError();
3330 OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, "
3331 "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(),
3332 pFile, pFile->pMapRegion));
3333 return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
3334 "winSync1", pFile->zPath);
3335 }
3336 }
3337#endif
mistachkin318507b2011-11-11 22:08:543338 rc = osFlushFileBuffers(pFile->h);
shaneh9dd6e082011-04-15 20:18:403339 SimulateIOError( rc=FALSE );
3340 if( rc ){
mistachkinad1e55e2015-03-27 18:20:253341 OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
3342 osGetCurrentProcessId(), pFile, pFile->h));
drhbbd42a62004-05-22 17:41:583343 return SQLITE_OK;
3344 }else{
mistachkin318507b2011-11-11 22:08:543345 pFile->lastErrno = osGetLastError();
mistachkinad1e55e2015-03-27 18:20:253346 OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_FSYNC\n",
3347 osGetCurrentProcessId(), pFile, pFile->h));
mistachkin2aef9972011-11-10 20:21:203348 return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno,
mistachkinccb43712015-03-26 23:36:353349 "winSync2", pFile->zPath);
drhbbd42a62004-05-22 17:41:583350 }
shane84ca3832008-11-13 18:20:433351#endif
drhbbd42a62004-05-22 17:41:583352}
3353
3354/*
drhbbd42a62004-05-22 17:41:583355** Determine the current size of a file in bytes
3356*/
drh153c62c2007-08-24 03:51:333357static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
3358 winFile *pFile = (winFile*)id;
drh24560d12012-03-01 22:44:563359 int rc = SQLITE_OK;
shane50daafc2009-03-05 05:54:553360
3361 assert( id!=0 );
mistachkinf2c1c992013-04-28 01:44:433362 assert( pSize!=0 );
drh9cce7102007-01-09 17:18:193363 SimulateIOError(return SQLITE_IOERR_FSTAT);
mistachkinf2c1c992013-04-28 01:44:433364 OSTRACE(("SIZE file=%p, pSize=%p\n", pFile->h, pSize));
3365
drh24560d12012-03-01 22:44:563366#if SQLITE_OS_WINRT
shane9db299f2009-01-30 05:59:103367 {
drh24560d12012-03-01 22:44:563368 FILE_STANDARD_INFO info;
mistachkin75b70a22012-03-02 13:47:163369 if( osGetFileInformationByHandleEx(pFile->h, FileStandardInfo,
drh24560d12012-03-01 22:44:563370 &info, sizeof(info)) ){
3371 *pSize = info.EndOfFile.QuadPart;
3372 }else{
mistachkin75b70a22012-03-02 13:47:163373 pFile->lastErrno = osGetLastError();
drh24560d12012-03-01 22:44:563374 rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno,
3375 "winFileSize", pFile->zPath);
3376 }
shane9db299f2009-01-30 05:59:103377 }
drh24560d12012-03-01 22:44:563378#else
3379 {
3380 DWORD upperBits;
3381 DWORD lowerBits;
3382 DWORD lastErrno;
3383
3384 lowerBits = osGetFileSize(pFile->h, &upperBits);
3385 *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits;
3386 if( (lowerBits == INVALID_FILE_SIZE)
3387 && ((lastErrno = osGetLastError())!=NO_ERROR) ){
3388 pFile->lastErrno = lastErrno;
3389 rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno,
mistachkin9f11ef12013-08-31 02:48:563390 "winFileSize", pFile->zPath);
drh24560d12012-03-01 22:44:563391 }
3392 }
3393#endif
mistachkinf2c1c992013-04-28 01:44:433394 OSTRACE(("SIZE file=%p, pSize=%p, *pSize=%lld, rc=%s\n",
3395 pFile->h, pSize, *pSize, sqlite3ErrName(rc)));
drh24560d12012-03-01 22:44:563396 return rc;
drhbbd42a62004-05-22 17:41:583397}
3398
3399/*
drh602bbd32006-01-06 20:22:293400** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems.
3401*/
3402#ifndef LOCKFILE_FAIL_IMMEDIATELY
3403# define LOCKFILE_FAIL_IMMEDIATELY 1
3404#endif
3405
mistachkin2a5cfb32012-03-02 22:38:493406#ifndef LOCKFILE_EXCLUSIVE_LOCK
3407# define LOCKFILE_EXCLUSIVE_LOCK 2
3408#endif
3409
3410/*
3411** Historically, SQLite has used both the LockFile and LockFileEx functions.
3412** When the LockFile function was used, it was always expected to fail
3413** immediately if the lock could not be obtained. Also, it always expected to
3414** obtain an exclusive lock. These flags are used with the LockFileEx function
3415** and reflect those expectations; therefore, they should not be changed.
3416*/
3417#ifndef SQLITE_LOCKFILE_FLAGS
3418# define SQLITE_LOCKFILE_FLAGS (LOCKFILE_FAIL_IMMEDIATELY | \
3419 LOCKFILE_EXCLUSIVE_LOCK)
3420#endif
3421
3422/*
3423** Currently, SQLite never calls the LockFileEx function without wanting the
3424** call to fail immediately if the lock cannot be obtained.
3425*/
3426#ifndef SQLITE_LOCKFILEEX_FLAGS
3427# define SQLITE_LOCKFILEEX_FLAGS (LOCKFILE_FAIL_IMMEDIATELY)
3428#endif
3429
drh602bbd32006-01-06 20:22:293430/*
drh9c105bb2004-10-02 20:38:283431** Acquire a reader lock.
drh51c6d962004-06-06 00:42:253432** Different API routines are called depending on whether or not this
mistachkin6c3c1a02011-11-12 03:17:403433** is Win9x or WinNT.
drh51c6d962004-06-06 00:42:253434*/
dan2d878942025-02-10 20:46:143435static int winGetReadLock(winFile *pFile, int bBlock){
drh51c6d962004-06-06 00:42:253436 int res;
dan2d878942025-02-10 20:46:143437 DWORD mask = ~(bBlock ? LOCKFILE_FAIL_IMMEDIATELY : 0);
mistachkinf2c1c992013-04-28 01:44:433438 OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype));
mistachkinb324bc72013-08-28 02:37:293439 if( osIsNT() ){
mistachkina7494862012-04-18 05:57:383440#if SQLITE_OS_WINCE
3441 /*
3442 ** NOTE: Windows CE is handled differently here due its lack of the Win32
3443 ** API LockFileEx.
3444 */
3445 res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0);
3446#else
dan2d878942025-02-10 20:46:143447 res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS&mask, SHARED_FIRST, 0,
mistachkin2a5cfb32012-03-02 22:38:493448 SHARED_SIZE, 0);
mistachkina7494862012-04-18 05:57:383449#endif
drhd52ee722012-03-02 00:00:473450 }
3451#ifdef SQLITE_WIN32_HAS_ANSI
3452 else{
drh9c105bb2004-10-02 20:38:283453 int lk;
drh2fa18682008-03-19 14:15:343454 sqlite3_randomness(sizeof(lk), &lk);
drh1bd10f82008-12-10 21:19:563455 pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1));
dan2d878942025-02-10 20:46:143456 res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS&mask,
mistachkin2a5cfb32012-03-02 22:38:493457 SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
drh51c6d962004-06-06 00:42:253458 }
drhd52ee722012-03-02 00:00:473459#endif
shane9db299f2009-01-30 05:59:103460 if( res == 0 ){
mistachkin318507b2011-11-11 22:08:543461 pFile->lastErrno = osGetLastError();
drh50990db2011-04-13 20:26:133462 /* No need to log a failure to lock */
shane9db299f2009-01-30 05:59:103463 }
mistachkinff0bc8f2014-05-28 03:23:553464 OSTRACE(("READ-LOCK file=%p, result=%d\n", pFile->h, res));
drh51c6d962004-06-06 00:42:253465 return res;
3466}
3467
3468/*
3469** Undo a readlock
3470*/
mistachkinb324bc72013-08-28 02:37:293471static int winUnlockReadLock(winFile *pFile){
drh51c6d962004-06-06 00:42:253472 int res;
mistachkind1ef9b62011-11-21 00:54:373473 DWORD lastErrno;
mistachkinf2c1c992013-04-28 01:44:433474 OSTRACE(("READ-UNLOCK file=%p, lock=%d\n", pFile->h, pFile->locktype));
mistachkinb324bc72013-08-28 02:37:293475 if( osIsNT() ){
mistachkina7494862012-04-18 05:57:383476 res = winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
drh51c6d962004-06-06 00:42:253477 }
drhd52ee722012-03-02 00:00:473478#ifdef SQLITE_WIN32_HAS_ANSI
3479 else{
mistachkina7494862012-04-18 05:57:383480 res = winUnlockFile(&pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
drhd52ee722012-03-02 00:00:473481 }
3482#endif
mistachkind1ef9b62011-11-21 00:54:373483 if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){
3484 pFile->lastErrno = lastErrno;
mistachkin2aef9972011-11-10 20:21:203485 winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno,
mistachkin9f11ef12013-08-31 02:48:563486 "winUnlockReadLock", pFile->zPath);
shane9db299f2009-01-30 05:59:103487 }
mistachkinff0bc8f2014-05-28 03:23:553488 OSTRACE(("READ-UNLOCK file=%p, result=%d\n", pFile->h, res));
drh51c6d962004-06-06 00:42:253489 return res;
3490}
3491
tpoindex9a09a3c2004-12-20 19:01:323492/*
drhb3e04342004-06-08 00:47:473493** Lock the file with the lock specified by parameter locktype - one
3494** of the following:
3495**
3496** (1) SHARED_LOCK
3497** (2) RESERVED_LOCK
3498** (3) PENDING_LOCK
3499** (4) EXCLUSIVE_LOCK
3500**
3501** Sometimes when requesting one lock state, additional lock states
3502** are inserted in between. The locking might fail on one of the later
3503** transitions leaving the lock state different from what it started but
3504** still short of its goal. The following chart shows the allowed
3505** transitions and the inserted intermediate states:
3506**
3507** UNLOCKED -> SHARED
3508** SHARED -> RESERVED
3509** SHARED -> (PENDING) -> EXCLUSIVE
3510** RESERVED -> (PENDING) -> EXCLUSIVE
3511** PENDING -> EXCLUSIVE
3512**
drh9c06c952005-11-26 00:25:003513** This routine will only increase a lock. The winUnlock() routine
drhb3e04342004-06-08 00:47:473514** erases all locks at once and returns us immediately to locking level 0.
3515** It is not possible to lower the locking level one step at a time. You
3516** must go straight to locking level 0.
drh51c6d962004-06-06 00:42:253517*/
drh153c62c2007-08-24 03:51:333518static int winLock(sqlite3_file *id, int locktype){
drh51c6d962004-06-06 00:42:253519 int rc = SQLITE_OK; /* Return code from subroutines */
mistachkin318507b2011-11-11 22:08:543520 int res = 1; /* Result of a Windows lock call */
drh153c62c2007-08-24 03:51:333521 int newLocktype; /* Set pFile->locktype to this value before exiting */
drhe54ca3f2004-06-07 01:52:143522 int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
drh054889e2005-11-30 03:20:313523 winFile *pFile = (winFile*)id;
mistachkind1ef9b62011-11-21 00:54:373524 DWORD lastErrno = NO_ERROR;
drh51c6d962004-06-06 00:42:253525
shane50daafc2009-03-05 05:54:553526 assert( id!=0 );
mistachkinf2c1c992013-04-28 01:44:433527 OSTRACE(("LOCK file=%p, oldLock=%d(%d), newLock=%d\n",
3528 pFile->h, pFile->locktype, pFile->sharedLockByte, locktype));
drh51c6d962004-06-06 00:42:253529
3530 /* If there is already a lock of this type or more restrictive on the
3531 ** OsFile, do nothing. Don't use the end_lock: exit path, as
3532 ** sqlite3OsEnterMutex() hasn't been called yet.
3533 */
drh054889e2005-11-30 03:20:313534 if( pFile->locktype>=locktype ){
mistachkinf2c1c992013-04-28 01:44:433535 OSTRACE(("LOCK-HELD file=%p, rc=SQLITE_OK\n", pFile->h));
drh51c6d962004-06-06 00:42:253536 return SQLITE_OK;
3537 }
3538
drh275fe3a2015-05-28 00:54:353539 /* Do not allow any kind of write-lock on a read-only database
3540 */
3541 if( (pFile->ctrlFlags & WINFILE_RDONLY)!=0 && locktype>=RESERVED_LOCK ){
3542 return SQLITE_IOERR_LOCK;
3543 }
3544
drhb3e04342004-06-08 00:47:473545 /* Make sure the locking sequence is correct
3546 */
drh054889e2005-11-30 03:20:313547 assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
drhb3e04342004-06-08 00:47:473548 assert( locktype!=PENDING_LOCK );
drh054889e2005-11-30 03:20:313549 assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
drhb3e04342004-06-08 00:47:473550
dan8bbce212025-02-12 17:21:243551 /* Lock the PENDING_LOCK byte if we need to acquire an EXCLUSIVE lock or
drh51c6d962004-06-06 00:42:253552 ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of
3553 ** the PENDING_LOCK byte is temporary.
3554 */
drh054889e2005-11-30 03:20:313555 newLocktype = pFile->locktype;
dan8bbce212025-02-12 17:21:243556 if( locktype==SHARED_LOCK
3557 || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK)
drhe54ca3f2004-06-07 01:52:143558 ){
drhb3e04342004-06-08 00:47:473559 int cnt = 3;
dan8bbce212025-02-12 17:21:243560
3561 /* Flags for the LockFileEx() call. This should be an exclusive lock if
3562 ** this call is to obtain EXCLUSIVE, or a shared lock if this call is to
3563 ** obtain SHARED. */
3564 int flags = LOCKFILE_FAIL_IMMEDIATELY;
3565 if( locktype==EXCLUSIVE_LOCK ){
3566 flags |= LOCKFILE_EXCLUSIVE_LOCK;
3567 }
3568 while( cnt>0 ){
drhd6ca4b92011-11-09 18:07:343569 /* Try 3 times to get the pending lock. This is needed to work
mistachkin318507b2011-11-11 22:08:543570 ** around problems caused by indexing and/or anti-virus software on
3571 ** Windows systems.
dan8bbce212025-02-12 17:21:243572 **
drhd6ca4b92011-11-09 18:07:343573 ** If you are using this code as a model for alternative VFSes, do not
dan8bbce212025-02-12 17:21:243574 ** copy this retry logic. It is a hack intended for Windows only. */
3575 res = winLockFile(&pFile->h, flags, PENDING_BYTE, 0, 1, 0);
3576 if( res ) break;
3577
mistachkin8e86b6a2014-05-28 03:27:423578 lastErrno = osGetLastError();
dan8bbce212025-02-12 17:21:243579 OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, result=%d\n",
3580 pFile->h, cnt, res
3581 ));
3582
mistachkin8e86b6a2014-05-28 03:27:423583 if( lastErrno==ERROR_INVALID_HANDLE ){
3584 pFile->lastErrno = lastErrno;
3585 rc = SQLITE_IOERR_LOCK;
dan8bbce212025-02-12 17:21:243586 OSTRACE(("LOCK-FAIL file=%p, count=%d, rc=%s\n",
3587 pFile->h, cnt, sqlite3ErrName(rc)
3588 ));
mistachkin8e86b6a2014-05-28 03:27:423589 return rc;
3590 }
dan8bbce212025-02-12 17:21:243591
3592 cnt--;
3593 if( cnt>0 ) sqlite3_win32_sleep(1);
drhbbd42a62004-05-22 17:41:583594 }
drhe54ca3f2004-06-07 01:52:143595 gotPendingLock = res;
drh51c6d962004-06-06 00:42:253596 }
3597
3598 /* Acquire a shared lock
3599 */
drhb3e04342004-06-08 00:47:473600 if( locktype==SHARED_LOCK && res ){
drh054889e2005-11-30 03:20:313601 assert( pFile->locktype==NO_LOCK );
danf0374402025-02-24 21:27:163602#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
dan2d878942025-02-10 20:46:143603 res = winGetReadLock(pFile, pFile->bBlockOnConnect);
danf0374402025-02-24 21:27:163604#else
3605 res = winGetReadLock(pFile, 0);
3606#endif
drhe54ca3f2004-06-07 01:52:143607 if( res ){
3608 newLocktype = SHARED_LOCK;
shane9db299f2009-01-30 05:59:103609 }else{
mistachkind1ef9b62011-11-21 00:54:373610 lastErrno = osGetLastError();
drh51c6d962004-06-06 00:42:253611 }
3612 }
3613
3614 /* Acquire a RESERVED lock
3615 */
drhb3e04342004-06-08 00:47:473616 if( locktype==RESERVED_LOCK && res ){
drh054889e2005-11-30 03:20:313617 assert( pFile->locktype==SHARED_LOCK );
mistachkina7494862012-04-18 05:57:383618 res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, RESERVED_BYTE, 0, 1, 0);
drhe54ca3f2004-06-07 01:52:143619 if( res ){
3620 newLocktype = RESERVED_LOCK;
shane9db299f2009-01-30 05:59:103621 }else{
mistachkind1ef9b62011-11-21 00:54:373622 lastErrno = osGetLastError();
drhe54ca3f2004-06-07 01:52:143623 }
3624 }
3625
3626 /* Acquire a PENDING lock
3627 */
drhb3e04342004-06-08 00:47:473628 if( locktype==EXCLUSIVE_LOCK && res ){
drhe54ca3f2004-06-07 01:52:143629 newLocktype = PENDING_LOCK;
3630 gotPendingLock = 0;
drh51c6d962004-06-06 00:42:253631 }
3632
3633 /* Acquire an EXCLUSIVE lock
3634 */
drhe54ca3f2004-06-07 01:52:143635 if( locktype==EXCLUSIVE_LOCK && res ){
drh054889e2005-11-30 03:20:313636 assert( pFile->locktype>=SHARED_LOCK );
drh56a41072023-06-16 14:39:213637 (void)winUnlockReadLock(pFile);
mistachkina7494862012-04-18 05:57:383638 res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0,
mistachkin2a5cfb32012-03-02 22:38:493639 SHARED_SIZE, 0);
drhe54ca3f2004-06-07 01:52:143640 if( res ){
3641 newLocktype = EXCLUSIVE_LOCK;
3642 }else{
mistachkind1ef9b62011-11-21 00:54:373643 lastErrno = osGetLastError();
dan2d878942025-02-10 20:46:143644 winGetReadLock(pFile, 0);
drhe54ca3f2004-06-07 01:52:143645 }
3646 }
3647
3648 /* If we are holding a PENDING lock that ought to be released, then
3649 ** release it now.
3650 */
drhb3e04342004-06-08 00:47:473651 if( gotPendingLock && locktype==SHARED_LOCK ){
mistachkina7494862012-04-18 05:57:383652 winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0);
drh51c6d962004-06-06 00:42:253653 }
3654
3655 /* Update the state of the lock has held in the file descriptor then
3656 ** return the appropriate result code.
3657 */
3658 if( res ){
drh51c6d962004-06-06 00:42:253659 rc = SQLITE_OK;
3660 }else{
mistachkind1ef9b62011-11-21 00:54:373661 pFile->lastErrno = lastErrno;
drh51c6d962004-06-06 00:42:253662 rc = SQLITE_BUSY;
mistachkin533fb6d2013-08-28 02:26:483663 OSTRACE(("LOCK-FAIL file=%p, wanted=%d, got=%d\n",
3664 pFile->h, locktype, newLocktype));
drhbbd42a62004-05-22 17:41:583665 }
drh1bd10f82008-12-10 21:19:563666 pFile->locktype = (u8)newLocktype;
mistachkinf2c1c992013-04-28 01:44:433667 OSTRACE(("LOCK file=%p, lock=%d, rc=%s\n",
3668 pFile->h, pFile->locktype, sqlite3ErrName(rc)));
drhbbd42a62004-05-22 17:41:583669 return rc;
3670}
3671
3672/*
drh51c6d962004-06-06 00:42:253673** This routine checks if there is a RESERVED lock held on the specified
3674** file by this or any other process. If such a lock is held, return
3675** non-zero, otherwise zero.
drhbbd42a62004-05-22 17:41:583676*/
danielk1977861f7452008-06-05 11:39:113677static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
mistachkinff0bc8f2014-05-28 03:23:553678 int res;
drh054889e2005-11-30 03:20:313679 winFile *pFile = (winFile*)id;
shane50daafc2009-03-05 05:54:553680
shanehe2ad9312010-07-08 03:13:333681 SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
mistachkinf2c1c992013-04-28 01:44:433682 OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p\n", pFile->h, pResOut));
shanehe2ad9312010-07-08 03:13:333683
shane50daafc2009-03-05 05:54:553684 assert( id!=0 );
drh054889e2005-11-30 03:20:313685 if( pFile->locktype>=RESERVED_LOCK ){
mistachkinff0bc8f2014-05-28 03:23:553686 res = 1;
3687 OSTRACE(("TEST-WR-LOCK file=%p, result=%d (local)\n", pFile->h, res));
drhbbd42a62004-05-22 17:41:583688 }else{
drh62aaa6c2015-11-21 17:27:423689 res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE,0,1,0);
mistachkinff0bc8f2014-05-28 03:23:553690 if( res ){
mistachkina7494862012-04-18 05:57:383691 winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
drhbbd42a62004-05-22 17:41:583692 }
mistachkinff0bc8f2014-05-28 03:23:553693 res = !res;
3694 OSTRACE(("TEST-WR-LOCK file=%p, result=%d (remote)\n", pFile->h, res));
drhbbd42a62004-05-22 17:41:583695 }
mistachkinff0bc8f2014-05-28 03:23:553696 *pResOut = res;
mistachkinf2c1c992013-04-28 01:44:433697 OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
3698 pFile->h, pResOut, *pResOut));
danielk1977861f7452008-06-05 11:39:113699 return SQLITE_OK;
drhbbd42a62004-05-22 17:41:583700}
3701
3702/*
drha6abd042004-06-09 17:37:223703** Lower the locking level on file descriptor id to locktype. locktype
3704** must be either NO_LOCK or SHARED_LOCK.
3705**
3706** If the locking level of the file descriptor is already at or below
3707** the requested locking level, this routine is a no-op.
3708**
drh9c105bb2004-10-02 20:38:283709** It is not possible for this routine to fail if the second argument
3710** is NO_LOCK. If the second argument is SHARED_LOCK then this routine
3711** might return SQLITE_IOERR;
drhbbd42a62004-05-22 17:41:583712*/
drh153c62c2007-08-24 03:51:333713static int winUnlock(sqlite3_file *id, int locktype){
drh9c105bb2004-10-02 20:38:283714 int type;
drh054889e2005-11-30 03:20:313715 winFile *pFile = (winFile*)id;
drh153c62c2007-08-24 03:51:333716 int rc = SQLITE_OK;
drh054889e2005-11-30 03:20:313717 assert( pFile!=0 );
drha6abd042004-06-09 17:37:223718 assert( locktype<=SHARED_LOCK );
mistachkinf2c1c992013-04-28 01:44:433719 OSTRACE(("UNLOCK file=%p, oldLock=%d(%d), newLock=%d\n",
3720 pFile->h, pFile->locktype, pFile->sharedLockByte, locktype));
drh054889e2005-11-30 03:20:313721 type = pFile->locktype;
drhe54ca3f2004-06-07 01:52:143722 if( type>=EXCLUSIVE_LOCK ){
mistachkina7494862012-04-18 05:57:383723 winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
dan41f29802025-02-12 08:07:103724 if( locktype==SHARED_LOCK && !winGetReadLock(pFile, 0) ){
drh9c105bb2004-10-02 20:38:283725 /* This should never happen. We should always be able to
3726 ** reacquire the read lock */
mistachkin318507b2011-11-11 22:08:543727 rc = winLogError(SQLITE_IOERR_UNLOCK, osGetLastError(),
mistachkin9f11ef12013-08-31 02:48:563728 "winUnlock", pFile->zPath);
drh9c105bb2004-10-02 20:38:283729 }
drhbbd42a62004-05-22 17:41:583730 }
drhe54ca3f2004-06-07 01:52:143731 if( type>=RESERVED_LOCK ){
mistachkina7494862012-04-18 05:57:383732 winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
drh51c6d962004-06-06 00:42:253733 }
drh9c105bb2004-10-02 20:38:283734 if( locktype==NO_LOCK && type>=SHARED_LOCK ){
mistachkinb324bc72013-08-28 02:37:293735 winUnlockReadLock(pFile);
drh51c6d962004-06-06 00:42:253736 }
drhb3e04342004-06-08 00:47:473737 if( type>=PENDING_LOCK ){
mistachkina7494862012-04-18 05:57:383738 winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0);
drhb3e04342004-06-08 00:47:473739 }
drh1bd10f82008-12-10 21:19:563740 pFile->locktype = (u8)locktype;
mistachkinf2c1c992013-04-28 01:44:433741 OSTRACE(("UNLOCK file=%p, lock=%d, rc=%s\n",
3742 pFile->h, pFile->locktype, sqlite3ErrName(rc)));
drh9c105bb2004-10-02 20:38:283743 return rc;
drhbbd42a62004-05-22 17:41:583744}
3745
mistachkin1e754832016-07-08 21:14:373746/******************************************************************************
3747****************************** No-op Locking **********************************
3748**
3749** Of the various locking implementations available, this is by far the
3750** simplest: locking is ignored. No attempt is made to lock the database
3751** file for reading or writing.
3752**
3753** This locking mode is appropriate for use on read-only databases
3754** (ex: databases that are burned into CD-ROM, for example.) It can
3755** also be used if the application employs some external mechanism to
3756** prevent simultaneous access of the same database by two or more
3757** database connections. But there is a serious risk of database
3758** corruption if this locking mode is used in situations where multiple
3759** database connections are accessing the same database file at the same
3760** time and one or more of those connections are writing.
3761*/
3762
3763static int winNolockLock(sqlite3_file *id, int locktype){
3764 UNUSED_PARAMETER(id);
3765 UNUSED_PARAMETER(locktype);
3766 return SQLITE_OK;
3767}
3768
3769static int winNolockCheckReservedLock(sqlite3_file *id, int *pResOut){
3770 UNUSED_PARAMETER(id);
3771 UNUSED_PARAMETER(pResOut);
3772 return SQLITE_OK;
3773}
3774
3775static int winNolockUnlock(sqlite3_file *id, int locktype){
3776 UNUSED_PARAMETER(id);
3777 UNUSED_PARAMETER(locktype);
3778 return SQLITE_OK;
3779}
3780
3781/******************* End of the no-op lock implementation *********************
3782******************************************************************************/
3783
drhbbd42a62004-05-22 17:41:583784/*
peter.d.reid60ec9142014-09-06 16:39:463785** If *pArg is initially negative then this is a query. Set *pArg to
drhf12b3f62011-12-21 14:42:293786** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
3787**
3788** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
3789*/
3790static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){
3791 if( *pArg<0 ){
3792 *pArg = (pFile->ctrlFlags & mask)!=0;
3793 }else if( (*pArg)==0 ){
3794 pFile->ctrlFlags &= ~mask;
3795 }else{
3796 pFile->ctrlFlags |= mask;
3797 }
3798}
3799
mistachkind95a3d32013-08-30 21:52:383800/* Forward references to VFS helper methods used for temporary files */
mistachkin37418272013-08-28 05:49:393801static int winGetTempname(sqlite3_vfs *, char **);
mistachkind95a3d32013-08-30 21:52:383802static int winIsDir(const void *);
mistachkina8e41ec2020-05-15 01:18:073803static BOOL winIsLongPathPrefix(const char *);
mistachkind95a3d32013-08-30 21:52:383804static BOOL winIsDriveLetterAndColon(const char *);
drh696b33e2012-12-06 19:01:423805
drhf12b3f62011-12-21 14:42:293806/*
drh9e33c2c2007-08-31 18:34:593807** Control and query of the open file handle.
drh0ccebe72005-06-07 22:22:503808*/
drh9e33c2c2007-08-31 18:34:593809static int winFileControl(sqlite3_file *id, int op, void *pArg){
drhf0b190d2011-07-26 16:03:073810 winFile *pFile = (winFile*)id;
mistachkinf2c1c992013-04-28 01:44:433811 OSTRACE(("FCNTL file=%p, op=%d, pArg=%p\n", pFile->h, op, pArg));
drh9e33c2c2007-08-31 18:34:593812 switch( op ){
3813 case SQLITE_FCNTL_LOCKSTATE: {
drhf0b190d2011-07-26 16:03:073814 *(int*)pArg = pFile->locktype;
mistachkinf2c1c992013-04-28 01:44:433815 OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
drh9e33c2c2007-08-31 18:34:593816 return SQLITE_OK;
3817 }
mistachkinb7b91062016-03-15 19:10:393818 case SQLITE_FCNTL_LAST_ERRNO: {
drhf0b190d2011-07-26 16:03:073819 *(int*)pArg = (int)pFile->lastErrno;
mistachkinf2c1c992013-04-28 01:44:433820 OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
shane9db299f2009-01-30 05:59:103821 return SQLITE_OK;
3822 }
dan502019c2010-07-28 14:26:173823 case SQLITE_FCNTL_CHUNK_SIZE: {
drhf0b190d2011-07-26 16:03:073824 pFile->szChunk = *(int *)pArg;
mistachkinf2c1c992013-04-28 01:44:433825 OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
dan502019c2010-07-28 14:26:173826 return SQLITE_OK;
3827 }
drhf5d6e472010-05-19 19:39:263828 case SQLITE_FCNTL_SIZE_HINT: {
mistachkind589a542011-08-30 01:23:343829 if( pFile->szChunk>0 ){
mistachkind589a542011-08-30 01:23:343830 sqlite3_int64 oldSz;
3831 int rc = winFileSize(id, &oldSz);
3832 if( rc==SQLITE_OK ){
3833 sqlite3_int64 newSz = *(sqlite3_int64*)pArg;
3834 if( newSz>oldSz ){
3835 SimulateIOErrorBenign(1);
3836 rc = winTruncate(id, newSz);
3837 SimulateIOErrorBenign(0);
3838 }
mistachkin4458bc82011-08-25 01:16:423839 }
mistachkinf2c1c992013-04-28 01:44:433840 OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
mistachkind589a542011-08-30 01:23:343841 return rc;
mistachkin4458bc82011-08-25 01:16:423842 }
mistachkinf2c1c992013-04-28 01:44:433843 OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
mistachkind589a542011-08-30 01:23:343844 return SQLITE_OK;
drhf5d6e472010-05-19 19:39:263845 }
drhf0b190d2011-07-26 16:03:073846 case SQLITE_FCNTL_PERSIST_WAL: {
drhf12b3f62011-12-21 14:42:293847 winModeBit(pFile, WINFILE_PERSIST_WAL, (int*)pArg);
mistachkinf2c1c992013-04-28 01:44:433848 OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
drhf12b3f62011-12-21 14:42:293849 return SQLITE_OK;
3850 }
drhcb15f352011-12-23 01:04:173851 case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
3852 winModeBit(pFile, WINFILE_PSOW, (int*)pArg);
mistachkinf2c1c992013-04-28 01:44:433853 OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
drhf0b190d2011-07-26 16:03:073854 return SQLITE_OK;
3855 }
drhde60fc22011-12-14 17:53:363856 case SQLITE_FCNTL_VFSNAME: {
mistachkin40138752013-12-09 21:48:493857 *(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName);
mistachkinf2c1c992013-04-28 01:44:433858 OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
drhde60fc22011-12-14 17:53:363859 return SQLITE_OK;
3860 }
drhd0cdf012011-07-13 16:03:463861 case SQLITE_FCNTL_WIN32_AV_RETRY: {
3862 int *a = (int*)pArg;
3863 if( a[0]>0 ){
mistachkinb324bc72013-08-28 02:37:293864 winIoerrRetry = a[0];
drhd0cdf012011-07-13 16:03:463865 }else{
mistachkinb324bc72013-08-28 02:37:293866 a[0] = winIoerrRetry;
drhd0cdf012011-07-13 16:03:463867 }
3868 if( a[1]>0 ){
mistachkinb324bc72013-08-28 02:37:293869 winIoerrRetryDelay = a[1];
drhd0cdf012011-07-13 16:03:463870 }else{
mistachkinb324bc72013-08-28 02:37:293871 a[1] = winIoerrRetryDelay;
drhd0cdf012011-07-13 16:03:463872 }
mistachkinf2c1c992013-04-28 01:44:433873 OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
drhd0cdf012011-07-13 16:03:463874 return SQLITE_OK;
3875 }
mistachkin1b361ff2016-05-03 19:36:543876 case SQLITE_FCNTL_WIN32_GET_HANDLE: {
3877 LPHANDLE phFile = (LPHANDLE)pArg;
3878 *phFile = pFile->h;
3879 OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
3880 return SQLITE_OK;
3881 }
mistachkin6b98d672014-05-30 16:42:353882#ifdef SQLITE_TEST
3883 case SQLITE_FCNTL_WIN32_SET_HANDLE: {
3884 LPHANDLE phFile = (LPHANDLE)pArg;
3885 HANDLE hOldFile = pFile->h;
3886 pFile->h = *phFile;
3887 *phFile = hOldFile;
3888 OSTRACE(("FCNTL oldFile=%p, newFile=%p, rc=SQLITE_OK\n",
3889 hOldFile, pFile->h));
3890 return SQLITE_OK;
3891 }
3892#endif
drh1b37bc02024-11-13 14:58:353893 case SQLITE_FCNTL_NULL_IO: {
3894 (void)osCloseHandle(pFile->h);
3895 pFile->h = NULL;
3896 return SQLITE_OK;
3897 }
drh696b33e2012-12-06 19:01:423898 case SQLITE_FCNTL_TEMPFILENAME: {
mistachkin37418272013-08-28 05:49:393899 char *zTFile = 0;
3900 int rc = winGetTempname(pFile->pVfs, &zTFile);
3901 if( rc==SQLITE_OK ){
drh696b33e2012-12-06 19:01:423902 *(char**)pArg = zTFile;
3903 }
mistachkin9f11ef12013-08-31 02:48:563904 OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
mistachkin37418272013-08-28 05:49:393905 return rc;
drh696b33e2012-12-06 19:01:423906 }
mistachkin5824e052013-04-15 20:08:273907#if SQLITE_MAX_MMAP_SIZE>0
drh9b4c59f2013-04-15 17:03:423908 case SQLITE_FCNTL_MMAP_SIZE: {
drh34f74902013-04-03 13:09:183909 i64 newLimit = *(i64*)pArg;
drh34e258c2013-05-23 01:40:533910 int rc = SQLITE_OK;
drh9b4c59f2013-04-15 17:03:423911 if( newLimit>sqlite3GlobalConfig.mxMmap ){
3912 newLimit = sqlite3GlobalConfig.mxMmap;
3913 }
mistachkine35395a2017-08-07 19:06:543914
3915 /* The value of newLimit may be eventually cast to (SIZE_T) and passed
3916 ** to MapViewOfFile(). Restrict its value to 2GB if (SIZE_T) is not at
3917 ** least a 64-bit type. */
3918 if( newLimit>0 && sizeof(SIZE_T)<8 ){
3919 newLimit = (newLimit & 0x7FFFFFFF);
3920 }
3921
drh9b4c59f2013-04-15 17:03:423922 *(i64*)pArg = pFile->mmapSizeMax;
drh34e258c2013-05-23 01:40:533923 if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
3924 pFile->mmapSizeMax = newLimit;
3925 if( pFile->mmapSize>0 ){
mistachkinc2165662013-10-16 09:49:103926 winUnmapfile(pFile);
drh34e258c2013-05-23 01:40:533927 rc = winMapfile(pFile, -1);
3928 }
3929 }
mistachkin9f11ef12013-08-31 02:48:563930 OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
drh34e258c2013-05-23 01:40:533931 return rc;
drh5175b322013-04-01 17:22:513932 }
mistachkin5824e052013-04-15 20:08:273933#endif
dan6bd3faa2024-11-22 21:24:083934
3935#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
3936 case SQLITE_FCNTL_LOCK_TIMEOUT: {
3937 int iOld = pFile->iBusyTimeout;
dan46288882025-01-30 15:26:163938 int iNew = *(int*)pArg;
dan6bd3faa2024-11-22 21:24:083939#if SQLITE_ENABLE_SETLK_TIMEOUT==1
dan46288882025-01-30 15:26:163940 pFile->iBusyTimeout = (iNew < 0) ? INFINITE : (DWORD)iNew;
dan6bd3faa2024-11-22 21:24:083941#elif SQLITE_ENABLE_SETLK_TIMEOUT==2
dan46288882025-01-30 15:26:163942 pFile->iBusyTimeout = (DWORD)(!!iNew);
dan6bd3faa2024-11-22 21:24:083943#else
3944# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2"
3945#endif
3946 *(int*)pArg = iOld;
3947 return SQLITE_OK;
3948 }
dan2d878942025-02-10 20:46:143949 case SQLITE_FCNTL_BLOCK_ON_CONNECT: {
3950 int iNew = *(int*)pArg;
3951 pFile->bBlockOnConnect = iNew;
3952 return SQLITE_OK;
3953 }
3954#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */
dan6bd3faa2024-11-22 21:24:083955
drh9e33c2c2007-08-31 18:34:593956 }
mistachkinf2c1c992013-04-28 01:44:433957 OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h));
drh0b52b7d2011-01-26 19:46:223958 return SQLITE_NOTFOUND;
drh9cbe6352005-11-29 03:13:213959}
3960
3961/*
danielk1977a3d4c882007-03-23 10:08:383962** Return the sector size in bytes of the underlying block device for
3963** the specified file. This is almost always 512 bytes, but may be
3964** larger for some devices.
3965**
3966** SQLite code assumes this function cannot fail. It also assumes that
3967** if two files are created in the same file-system directory (i.e.
drh85b623f2007-12-13 21:54:093968** a database and its journal file) that the sector size will be the
danielk1977a3d4c882007-03-23 10:08:383969** same for both.
3970*/
drh153c62c2007-08-24 03:51:333971static int winSectorSize(sqlite3_file *id){
drh8942d412012-01-02 18:20:143972 (void)id;
3973 return SQLITE_DEFAULT_SECTOR_SIZE;
danielk1977a3d4c882007-03-23 10:08:383974}
3975
3976/*
drh153c62c2007-08-24 03:51:333977** Return a vector of device characteristics.
drh9c06c952005-11-26 00:25:003978*/
drh153c62c2007-08-24 03:51:333979static int winDeviceCharacteristics(sqlite3_file *id){
drhf12b3f62011-12-21 14:42:293980 winFile *p = (winFile*)id;
drh96501c82024-10-22 18:26:033981 return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN | SQLITE_IOCAP_SUBPAGE_READ |
drhcb15f352011-12-23 01:04:173982 ((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
drh153c62c2007-08-24 03:51:333983}
3984
mistachkin17835a52014-08-06 03:06:013985/*
shaneh420398c2010-09-03 04:29:303986** Windows will only let you create file view mappings
3987** on allocation size granularity boundaries.
3988** During sqlite3_os_init() we do a GetSystemInfo()
3989** to get the granularity size.
3990*/
mistachkin5dfd3d92014-02-05 11:05:473991static SYSTEM_INFO winSysInfo;
shaneh420398c2010-09-03 04:29:303992
mistachkin6e8752d2013-05-16 12:41:493993#ifndef SQLITE_OMIT_WAL
drh83235212010-05-14 16:34:343994
3995/*
3996** Helper functions to obtain and relinquish the global mutex. The
mistachkin17835a52014-08-06 03:06:013997** global mutex is used to protect the winLockInfo objects used by
drh83235212010-05-14 16:34:343998** this file, all of which may be shared by multiple threads.
3999**
mistachkin17835a52014-08-06 03:06:014000** Function winShmMutexHeld() is used to assert() that the global mutex
4001** is held when required. This function is only used as part of assert()
drh83235212010-05-14 16:34:344002** statements. e.g.
4003**
4004** winShmEnterMutex()
4005** assert( winShmMutexHeld() );
shanehd5a72402010-07-20 20:23:384006** winShmLeaveMutex()
drh83235212010-05-14 16:34:344007*/
mistachkin435666e2018-02-05 20:42:504008static sqlite3_mutex *winBigLock = 0;
drh83235212010-05-14 16:34:344009static void winShmEnterMutex(void){
mistachkin435666e2018-02-05 20:42:504010 sqlite3_mutex_enter(winBigLock);
drh83235212010-05-14 16:34:344011}
4012static void winShmLeaveMutex(void){
mistachkin435666e2018-02-05 20:42:504013 sqlite3_mutex_leave(winBigLock);
drh83235212010-05-14 16:34:344014}
mistachkin866b53e2014-01-14 10:17:024015#ifndef NDEBUG
drh83235212010-05-14 16:34:344016static int winShmMutexHeld(void) {
mistachkin435666e2018-02-05 20:42:504017 return sqlite3_mutex_held(winBigLock);
drh83235212010-05-14 16:34:344018}
4019#endif
4020
4021/*
4022** Object used to represent a single file opened and mmapped to provide
4023** shared memory. When multiple threads all reference the same
4024** log-summary, each thread has its own winFile object, but they all
4025** point to a single instance of this object. In other words, each
4026** log-summary is opened only once per process.
4027**
4028** winShmMutexHeld() must be true when creating or destroying
4029** this object or while reading or writing the following fields:
4030**
4031** nRef
mistachkin17835a52014-08-06 03:06:014032** pNext
drh83235212010-05-14 16:34:344033**
4034** The following fields are read-only after the object is created:
mistachkin17835a52014-08-06 03:06:014035**
drh83235212010-05-14 16:34:344036** zFilename
4037**
4038** Either winShmNode.mutex must be held or winShmNode.nRef==0 and
4039** winShmMutexHeld() is true when reading or writing any other field
4040** in this structure.
4041**
dand50eb9c2024-12-10 19:00:074042** File-handle hSharedShm is used to (a) take the DMS lock, (b) truncate
4043** the *-shm file if the DMS-locking protocol demands it, and (c) map
4044** regions of the *-shm file into memory using MapViewOfFile() or
4045** similar. Other locks are taken by individual clients using the
4046** winShm.hShm handles.
drh83235212010-05-14 16:34:344047*/
4048struct winShmNode {
4049 sqlite3_mutex *mutex; /* Mutex to access this object */
drh83235212010-05-14 16:34:344050 char *zFilename; /* Name of the file */
dana1801312024-11-30 20:00:544051 HANDLE hSharedShm; /* File handle open on zFilename */
dan9785fc92010-06-14 16:16:334052
dana1801312024-11-30 20:00:544053 int isUnlocked; /* DMS lock has not yet been obtained */
4054 int isReadonly; /* True if read-only */
dan9785fc92010-06-14 16:16:334055 int szRegion; /* Size of shared-memory regions */
4056 int nRegion; /* Size of array apRegion */
mistachkin4ff84312017-11-09 16:30:554057
dan9785fc92010-06-14 16:16:334058 struct ShmRegion {
4059 HANDLE hMap; /* File handle from CreateFileMapping */
4060 void *pMap;
4061 } *aRegion;
drh83235212010-05-14 16:34:344062 DWORD lastErrno; /* The Windows errno from the last I/O error */
dan9785fc92010-06-14 16:16:334063
drh83235212010-05-14 16:34:344064 int nRef; /* Number of winShm objects pointing to this */
drh83235212010-05-14 16:34:344065 winShmNode *pNext; /* Next in list of all winShmNode objects */
mistachkinfb383e92015-04-16 03:24:384066#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
drh83235212010-05-14 16:34:344067 u8 nextShmId; /* Next available winShm.id value */
4068#endif
4069};
4070
4071/*
4072** A global array of all winShmNode objects.
4073**
4074** The winShmMutexHeld() must be true while reading or writing this list.
4075*/
4076static winShmNode *winShmNodeList = 0;
4077
4078/*
4079** Structure used internally by this VFS to record the state of an
dand50eb9c2024-12-10 19:00:074080** open shared memory connection. There is one such structure for each
4081** winFile open on a wal mode database.
drh83235212010-05-14 16:34:344082*/
4083struct winShm {
4084 winShmNode *pShmNode; /* The underlying winShmNode object */
shaneh1f3e27b2010-07-12 20:46:334085 u16 sharedMask; /* Mask of shared locks held */
4086 u16 exclMask; /* Mask of exclusive locks held */
dana1801312024-11-30 20:00:544087 HANDLE hShm; /* File-handle on *-shm file. For locking. */
4088 int bReadonly; /* True if hShm is opened read-only */
mistachkinfb383e92015-04-16 03:24:384089#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
drh83235212010-05-14 16:34:344090 u8 id; /* Id of this connection with its winShmNode */
4091#endif
4092};
4093
4094/*
drh83235212010-05-14 16:34:344095** Constants used for locking
4096*/
drhbd9676c2010-06-23 17:58:384097#define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
drh20e1f082010-05-31 16:10:124098#define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
drh83235212010-05-14 16:34:344099
drh05cb5b22010-06-03 18:02:484100/* Forward references to VFS methods */
4101static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*);
4102static int winDelete(sqlite3_vfs *,const char*,int);
4103
drh83235212010-05-14 16:34:344104/*
4105** Purge the winShmNodeList list of all entries with winShmNode.nRef==0.
4106**
4107** This is not a VFS shared-memory method; it is a utility function called
4108** by VFS shared-memory methods.
4109*/
drh05cb5b22010-06-03 18:02:484110static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
drh83235212010-05-14 16:34:344111 winShmNode **pp;
4112 winShmNode *p;
4113 assert( winShmMutexHeld() );
mistachkine84d8d32013-04-29 03:09:104114 OSTRACE(("SHM-PURGE pid=%lu, deleteFlag=%d\n",
4115 osGetCurrentProcessId(), deleteFlag));
drh83235212010-05-14 16:34:344116 pp = &winShmNodeList;
4117 while( (p = *pp)!=0 ){
4118 if( p->nRef==0 ){
dan9785fc92010-06-14 16:16:334119 int i;
drh0353ed22013-10-16 11:31:514120 if( p->mutex ){ sqlite3_mutex_free(p->mutex); }
dan9785fc92010-06-14 16:16:334121 for(i=0; i<p->nRegion; i++){
mistachkin36ca5352013-09-12 01:47:574122 BOOL bRc = osUnmapViewOfFile(p->aRegion[i].pMap);
mistachkine84d8d32013-04-29 03:09:104123 OSTRACE(("SHM-PURGE-UNMAP pid=%lu, region=%d, rc=%s\n",
4124 osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
mistachkin36ca5352013-09-12 01:47:574125 UNUSED_VARIABLE_VALUE(bRc);
mistachkin318507b2011-11-11 22:08:544126 bRc = osCloseHandle(p->aRegion[i].hMap);
mistachkine84d8d32013-04-29 03:09:104127 OSTRACE(("SHM-PURGE-CLOSE pid=%lu, region=%d, rc=%s\n",
4128 osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
mistachkin36ca5352013-09-12 01:47:574129 UNUSED_VARIABLE_VALUE(bRc);
drh83235212010-05-14 16:34:344130 }
dance502822024-12-24 14:44:384131 winHandleClose(p->hSharedShm);
shanehe2ad9312010-07-08 03:13:334132 if( deleteFlag ){
4133 SimulateIOErrorBenign(1);
drh92c45cf2012-01-10 00:24:594134 sqlite3BeginBenignMalloc();
shanehe2ad9312010-07-08 03:13:334135 winDelete(pVfs, p->zFilename, 0);
drh92c45cf2012-01-10 00:24:594136 sqlite3EndBenignMalloc();
shanehe2ad9312010-07-08 03:13:334137 SimulateIOErrorBenign(0);
4138 }
drh83235212010-05-14 16:34:344139 *pp = p->pNext;
dan9785fc92010-06-14 16:16:334140 sqlite3_free(p->aRegion);
drh83235212010-05-14 16:34:344141 sqlite3_free(p);
4142 }else{
4143 pp = &p->pNext;
4144 }
4145 }
4146}
4147
drh83235212010-05-14 16:34:344148/*
dana1801312024-11-30 20:00:544149** The DMS lock has not yet been taken on the shm file associated with
4150** pShmNode. Take the lock. Truncate the *-shm file if required.
4151** Return SQLITE_OK if successful, or an SQLite error code otherwise.
mistachkin4ff84312017-11-09 16:30:554152*/
dan46288882025-01-30 15:26:164153static int winLockSharedMemory(winShmNode *pShmNode, DWORD nMs){
dana1801312024-11-30 20:00:544154 HANDLE h = pShmNode->hSharedShm;
4155 int rc = SQLITE_OK;
4156
dand50eb9c2024-12-10 19:00:074157 assert( sqlite3_mutex_held(pShmNode->mutex) );
4158 rc = winHandleLockTimeout(h, WIN_SHM_DMS, 1, 1, 0);
dana1801312024-11-30 20:00:544159 if( rc==SQLITE_OK ){
4160 /* We have an EXCLUSIVE lock on the DMS byte. This means that this
4161 ** is the first process to open the file. Truncate it to zero bytes
4162 ** in this case. */
4163 if( pShmNode->isReadonly ){
4164 rc = SQLITE_READONLY_CANTINIT;
4165 }else{
4166 rc = winHandleTruncate(h, 0);
4167 }
4168
4169 /* Release the EXCLUSIVE lock acquired above. */
4170 winUnlockFile(&h, WIN_SHM_DMS, 0, 1, 0);
4171 }else if( (rc & 0xFF)==SQLITE_BUSY ){
4172 rc = SQLITE_OK;
4173 }
mistachkin0e026f42017-11-09 23:24:294174
mistachkin7b7f2242017-11-09 22:23:504175 if( rc==SQLITE_OK ){
dana1801312024-11-30 20:00:544176 /* Take a SHARED lock on the DMS byte. */
dand50eb9c2024-12-10 19:00:074177 rc = winHandleLockTimeout(h, WIN_SHM_DMS, 1, 0, nMs);
dana1801312024-11-30 20:00:544178 if( rc==SQLITE_OK ){
4179 pShmNode->isUnlocked = 0;
mistachkin4ff84312017-11-09 16:30:554180 }
mistachkin4ff84312017-11-09 16:30:554181 }
4182
dana1801312024-11-30 20:00:544183 return rc;
4184}
mistachkin0e026f42017-11-09 23:24:294185
dana1801312024-11-30 20:00:544186
4187/*
4188** Convert a UTF-8 filename into whatever form the underlying
4189** operating system wants filenames in. Space to hold the result
4190** is obtained from malloc and must be freed by the calling
stephan42e5ceb2025-03-10 15:15:134191** function
4192**
4193** On Cygwin, 3 possible input forms are accepted:
4194** - If the filename starts with "<drive>:/" or "<drive>:\",
4195** it is converted to UTF-16 as-is.
4196** - If the filename contains '/', it is assumed to be a
4197** Cygwin absolute path, it is converted to a win32
4198** absolute path in UTF-16.
4199** - Otherwise it must be a filename only, the win32 filename
4200** is returned in UTF-16.
4201** Note: If the function cygwin_conv_path() fails, only
4202** UTF-8 -> UTF-16 conversion will be done. This can only
4203** happen when the file path >32k, in which case winUtf8ToUnicode()
4204** will fail too.
dana1801312024-11-30 20:00:544205*/
4206static void *winConvertFromUtf8Filename(const char *zFilename){
4207 void *zConverted = 0;
4208 if( osIsNT() ){
stephan42e5ceb2025-03-10 15:15:134209#ifdef __CYGWIN__
4210 int nChar;
4211 LPWSTR zWideFilename;
4212
4213 if( osCygwin_conv_path && !(winIsDriveLetterAndColon(zFilename)
4214 && winIsDirSep(zFilename[2])) ){
drh4a0b7a32025-05-19 14:50:364215 i64 nByte;
stephan42e5ceb2025-03-10 15:15:134216 int convertflag = CCP_POSIX_TO_WIN_W;
4217 if( !strchr(zFilename, '/') ) convertflag |= CCP_RELATIVE;
drh4a0b7a32025-05-19 14:50:364218 nByte = (i64)osCygwin_conv_path(convertflag,
stephan42e5ceb2025-03-10 15:15:134219 zFilename, 0, 0);
4220 if( nByte>0 ){
drh4a0b7a32025-05-19 14:50:364221 zConverted = sqlite3MallocZero(12+(u64)nByte);
stephan42e5ceb2025-03-10 15:15:134222 if ( zConverted==0 ){
4223 return zConverted;
4224 }
4225 zWideFilename = zConverted;
4226 /* Filenames should be prefixed, except when converted
4227 * full path already starts with "\\?\". */
4228 if( osCygwin_conv_path(convertflag, zFilename,
4229 zWideFilename+4, nByte)==0 ){
4230 if( (convertflag&CCP_RELATIVE) ){
4231 memmove(zWideFilename, zWideFilename+4, nByte);
4232 }else if( memcmp(zWideFilename+4, L"\\\\", 4) ){
4233 memcpy(zWideFilename, L"\\\\?\\", 8);
4234 }else if( zWideFilename[6]!='?' ){
4235 memmove(zWideFilename+6, zWideFilename+4, nByte);
4236 memcpy(zWideFilename, L"\\\\?\\UNC", 14);
4237 }else{
4238 memmove(zWideFilename, zWideFilename+4, nByte);
4239 }
4240 return zConverted;
4241 }
4242 sqlite3_free(zConverted);
4243 }
4244 }
4245 nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
4246 if( nChar==0 ){
4247 return 0;
4248 }
4249 zWideFilename = sqlite3MallocZero( nChar*sizeof(WCHAR)+12 );
4250 if( zWideFilename==0 ){
4251 return 0;
4252 }
4253 nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1,
4254 zWideFilename, nChar);
4255 if( nChar==0 ){
4256 sqlite3_free(zWideFilename);
4257 zWideFilename = 0;
4258 }else if( nChar>MAX_PATH
4259 && winIsDriveLetterAndColon(zFilename)
4260 && winIsDirSep(zFilename[2]) ){
4261 memmove(zWideFilename+4, zWideFilename, nChar*sizeof(WCHAR));
4262 zWideFilename[2] = '\\';
4263 memcpy(zWideFilename, L"\\\\?\\", 8);
4264 }else if( nChar>MAX_PATH
4265 && winIsDirSep(zFilename[0]) && winIsDirSep(zFilename[1])
4266 && zFilename[2] != '?' ){
4267 memmove(zWideFilename+6, zWideFilename, nChar*sizeof(WCHAR));
4268 memcpy(zWideFilename, L"\\\\?\\UNC", 14);
4269 }
4270 zConverted = zWideFilename;
4271#else
dana1801312024-11-30 20:00:544272 zConverted = winUtf8ToUnicode(zFilename);
stephan42e5ceb2025-03-10 15:15:134273#endif /* __CYGWIN__ */
dana1801312024-11-30 20:00:544274 }
stephan7b9407a2025-03-07 06:54:044275#if defined(SQLITE_WIN32_HAS_ANSI) && defined(_WIN32)
dana1801312024-11-30 20:00:544276 else{
4277 zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI());
4278 }
4279#endif
4280 /* caller will handle out of memory */
4281 return zConverted;
mistachkin4ff84312017-11-09 16:30:554282}
4283
4284/*
dan4ab343c2024-12-09 16:01:284285** This function is used to open a handle on a *-shm file.
drh83235212010-05-14 16:34:344286**
dance502822024-12-24 14:44:384287** If SQLITE_ENABLE_SETLK_TIMEOUT is defined at build time, then the file
4288** is opened with FILE_FLAG_OVERLAPPED specified. If not, it is not.
dan4ab343c2024-12-09 16:01:284289*/
4290static int winHandleOpen(
4291 const char *zUtf8, /* File to open */
4292 int *pbReadonly, /* IN/OUT: True for readonly handle */
4293 HANDLE *ph /* OUT: New HANDLE for file */
dana1801312024-11-30 20:00:544294){
4295 int rc = SQLITE_OK;
4296 void *zConverted = 0;
4297 int bReadonly = *pbReadonly;
4298 HANDLE h = INVALID_HANDLE_VALUE;
4299
dance502822024-12-24 14:44:384300#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
4301 const DWORD flag_overlapped = FILE_FLAG_OVERLAPPED;
4302#else
4303 const DWORD flag_overlapped = 0;
4304#endif
4305
dana1801312024-11-30 20:00:544306 /* Convert the filename to the system encoding. */
4307 zConverted = winConvertFromUtf8Filename(zUtf8);
4308 if( zConverted==0 ){
4309 OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8));
4310 rc = SQLITE_IOERR_NOMEM_BKPT;
4311 goto winopenfile_out;
mistachkin0e026f42017-11-09 23:24:294312 }
4313
dana1801312024-11-30 20:00:544314 /* Ensure the file we are trying to open is not actually a directory. */
4315 if( winIsDir(zConverted) ){
4316 OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8));
4317 rc = SQLITE_CANTOPEN_ISDIR;
4318 goto winopenfile_out;
4319 }
4320
4321 /* TODO: platforms.
4322 ** TODO: retry-on-ioerr.
4323 */
dan4ab343c2024-12-09 16:01:284324 if( osIsNT() ){
dan9d592352024-12-02 20:48:174325#if SQLITE_OS_WINRT
dan9d592352024-12-02 20:48:174326 CREATEFILE2_EXTENDED_PARAMETERS extendedParameters;
4327 memset(&extendedParameters, 0, sizeof(extendedParameters));
4328 extendedParameters.dwSize = sizeof(extendedParameters);
4329 extendedParameters.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
dance502822024-12-24 14:44:384330 extendedParameters.dwFileFlags = flag_overlapped;
dan9d592352024-12-02 20:48:174331 extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS;
4332 h = osCreateFile2((LPCWSTR)zConverted,
4333 (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)),/* dwDesiredAccess */
4334 FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */
4335 OPEN_ALWAYS, /* dwCreationDisposition */
4336 &extendedParameters
4337 );
dan9d592352024-12-02 20:48:174338#else
dan4ab343c2024-12-09 16:01:284339 h = osCreateFileW((LPCWSTR)zConverted, /* lpFileName */
4340 (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)), /* dwDesiredAccess */
4341 FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */
4342 NULL, /* lpSecurityAttributes */
4343 OPEN_ALWAYS, /* dwCreationDisposition */
dance502822024-12-24 14:44:384344 FILE_ATTRIBUTE_NORMAL|flag_overlapped,
dan4ab343c2024-12-09 16:01:284345 NULL
4346 );
dan9d592352024-12-02 20:48:174347#endif
dan4ab343c2024-12-09 16:01:284348 }else{
4349 /* Due to pre-processor directives earlier in this file,
4350 ** SQLITE_WIN32_HAS_ANSI is always defined if osIsNT() is false. */
4351#ifdef SQLITE_WIN32_HAS_ANSI
4352 h = osCreateFileA((LPCSTR)zConverted,
4353 (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)), /* dwDesiredAccess */
4354 FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */
4355 NULL, /* lpSecurityAttributes */
4356 OPEN_ALWAYS, /* dwCreationDisposition */
dance502822024-12-24 14:44:384357 FILE_ATTRIBUTE_NORMAL|flag_overlapped,
dan4ab343c2024-12-09 16:01:284358 NULL
4359 );
4360#endif
4361 }
4362
dana1801312024-11-30 20:00:544363 if( h==INVALID_HANDLE_VALUE ){
4364 if( bReadonly==0 ){
4365 bReadonly = 1;
dan4ab343c2024-12-09 16:01:284366 rc = winHandleOpen(zUtf8, &bReadonly, &h);
dana1801312024-11-30 20:00:544367 }else{
4368 rc = SQLITE_CANTOPEN_BKPT;
4369 }
4370 }
4371
4372 winopenfile_out:
4373 sqlite3_free(zConverted);
4374 *pbReadonly = bReadonly;
4375 *ph = h;
4376 return rc;
mistachkin4ff84312017-11-09 16:30:554377}
dana1801312024-11-30 20:00:544378
mistachkin4ff84312017-11-09 16:30:554379
4380/*
danda9fe0c2010-07-13 18:44:034381** Open the shared-memory area associated with database file pDbFd.
drh83235212010-05-14 16:34:344382*/
danda9fe0c2010-07-13 18:44:034383static int winOpenSharedMemory(winFile *pDbFd){
mistachkin10813712017-11-09 22:25:584384 struct winShm *p; /* The connection to be opened */
4385 winShmNode *pShmNode = 0; /* The underlying mmapped file */
4386 int rc = SQLITE_OK; /* Result code */
mistachkin10813712017-11-09 22:25:584387 winShmNode *pNew; /* Newly allocated winShmNode */
4388 int nName; /* Size of zName in bytes */
drh83235212010-05-14 16:34:344389
drh83235212010-05-14 16:34:344390 assert( pDbFd->pShm==0 ); /* Not previously opened */
4391
4392 /* Allocate space for the new sqlite3_shm object. Also speculatively
dana1801312024-11-30 20:00:544393 ** allocate space for a new winShmNode and filename. */
mistachkin7ea11af2012-09-13 15:24:294394 p = sqlite3MallocZero( sizeof(*p) );
mistachkinfad30392016-02-13 23:43:464395 if( p==0 ) return SQLITE_IOERR_NOMEM_BKPT;
drh83235212010-05-14 16:34:344396 nName = sqlite3Strlen30(pDbFd->zPath);
drhef86b942025-02-17 17:33:144397 pNew = sqlite3MallocZero( sizeof(*pShmNode) + (i64)nName + 17 );
drh83235212010-05-14 16:34:344398 if( pNew==0 ){
4399 sqlite3_free(p);
mistachkinfad30392016-02-13 23:43:464400 return SQLITE_IOERR_NOMEM_BKPT;
drh83235212010-05-14 16:34:344401 }
drh83235212010-05-14 16:34:344402 pNew->zFilename = (char*)&pNew[1];
dana1801312024-11-30 20:00:544403 pNew->hSharedShm = INVALID_HANDLE_VALUE;
4404 pNew->isUnlocked = 1;
drhd36f6602010-06-25 12:52:474405 sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
mistachkin17835a52014-08-06 03:06:014406 sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename);
drh83235212010-05-14 16:34:344407
dana1801312024-11-30 20:00:544408 /* Open a file-handle on the *-shm file for this connection. This file-handle
dan4ab343c2024-12-09 16:01:284409 ** is only used for locking. The mapping of the *-shm file is created using
4410 ** the shared file handle in winShmNode.hSharedShm. */
dana1801312024-11-30 20:00:544411 p->bReadonly = sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0);
dan4ab343c2024-12-09 16:01:284412 rc = winHandleOpen(pNew->zFilename, &p->bReadonly, &p->hShm);
dana1801312024-11-30 20:00:544413
drh83235212010-05-14 16:34:344414 /* Look to see if there is an existing winShmNode that can be used.
dana1801312024-11-30 20:00:544415 ** If no matching winShmNode currently exists, then create a new one. */
drh83235212010-05-14 16:34:344416 winShmEnterMutex();
4417 for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){
4418 /* TBD need to come up with better match here. Perhaps
dana1801312024-11-30 20:00:544419 ** use FILE_ID_BOTH_DIR_INFO Structure. */
drh83235212010-05-14 16:34:344420 if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break;
4421 }
dana1801312024-11-30 20:00:544422 if( pShmNode==0 ){
drh83235212010-05-14 16:34:344423 pShmNode = pNew;
drh83235212010-05-14 16:34:344424
dana1801312024-11-30 20:00:544425 /* Allocate a mutex for this winShmNode object, if one is required. */
drh97a7e5e2016-04-26 18:58:544426 if( sqlite3GlobalConfig.bCoreMutex ){
4427 pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
dana1801312024-11-30 20:00:544428 if( pShmNode->mutex==0 ) rc = SQLITE_IOERR_NOMEM_BKPT;
drh83235212010-05-14 16:34:344429 }
shaneh420398c2010-09-03 04:29:304430
dana1801312024-11-30 20:00:544431 /* Open a file-handle to use for mappings, and for the DMS lock. */
4432 if( rc==SQLITE_OK ){
4433 HANDLE h = INVALID_HANDLE_VALUE;
4434 pShmNode->isReadonly = p->bReadonly;
dan4ab343c2024-12-09 16:01:284435 rc = winHandleOpen(pNew->zFilename, &pShmNode->isReadonly, &h);
dana1801312024-11-30 20:00:544436 pShmNode->hSharedShm = h;
4437 }
4438
4439 /* If successful, link the new winShmNode into the global list. If an
4440 ** error occurred, free the object. */
4441 if( rc==SQLITE_OK ){
4442 pShmNode->pNext = winShmNodeList;
4443 winShmNodeList = pShmNode;
4444 pNew = 0;
mistachkin98e2cb82018-01-17 01:40:574445 }else{
dana1801312024-11-30 20:00:544446 sqlite3_mutex_free(pShmNode->mutex);
4447 if( pShmNode->hSharedShm!=INVALID_HANDLE_VALUE ){
4448 osCloseHandle(pShmNode->hSharedShm);
drh97a7e5e2016-04-26 18:58:544449 }
drh83235212010-05-14 16:34:344450 }
drh83235212010-05-14 16:34:344451 }
4452
dana1801312024-11-30 20:00:544453 /* If no error has occurred, link the winShm object to the winShmNode and
4454 ** the winShm to pDbFd. */
4455 if( rc==SQLITE_OK ){
4456 p->pShmNode = pShmNode;
dana1801312024-11-30 20:00:544457 pShmNode->nRef++;
mistachkinfb383e92015-04-16 03:24:384458#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
dana1801312024-11-30 20:00:544459 p->id = pShmNode->nextShmId++;
drh83235212010-05-14 16:34:344460#endif
dana1801312024-11-30 20:00:544461 pDbFd->pShm = p;
dan800bf8f2024-12-16 15:13:344462 }else if( p ){
dance502822024-12-24 14:44:384463 winHandleClose(p->hShm);
dana1801312024-11-30 20:00:544464 sqlite3_free(p);
4465 }
4466
4467 assert( rc!=SQLITE_OK || pShmNode->isUnlocked==0 || pShmNode->nRegion==0 );
drh83235212010-05-14 16:34:344468 winShmLeaveMutex();
drh83235212010-05-14 16:34:344469 sqlite3_free(pNew);
drh83235212010-05-14 16:34:344470 return rc;
4471}
4472
4473/*
mistachkin17835a52014-08-06 03:06:014474** Close a connection to shared-memory. Delete the underlying
drh83235212010-05-14 16:34:344475** storage if deleteFlag is true.
4476*/
drhe11fedc2010-07-14 00:14:304477static int winShmUnmap(
drh83235212010-05-14 16:34:344478 sqlite3_file *fd, /* Database holding shared memory */
4479 int deleteFlag /* Delete after closing if true */
4480){
4481 winFile *pDbFd; /* Database holding shared-memory */
4482 winShm *p; /* The connection to be closed */
4483 winShmNode *pShmNode; /* The underlying shared-memory file */
drh83235212010-05-14 16:34:344484
4485 pDbFd = (winFile*)fd;
4486 p = pDbFd->pShm;
shaneh1f3e27b2010-07-12 20:46:334487 if( p==0 ) return SQLITE_OK;
dana1801312024-11-30 20:00:544488 if( p->hShm!=INVALID_HANDLE_VALUE ){
4489 osCloseHandle(p->hShm);
4490 }
4491
drh83235212010-05-14 16:34:344492 pShmNode = p->pShmNode;
dana1801312024-11-30 20:00:544493 winShmEnterMutex();
drh83235212010-05-14 16:34:344494
4495 /* If pShmNode->nRef has reached 0, then close the underlying
dana1801312024-11-30 20:00:544496 ** shared-memory file, too. */
drh83235212010-05-14 16:34:344497 assert( pShmNode->nRef>0 );
4498 pShmNode->nRef--;
4499 if( pShmNode->nRef==0 ){
drh05cb5b22010-06-03 18:02:484500 winShmPurge(pDbFd->pVfs, deleteFlag);
drh83235212010-05-14 16:34:344501 }
4502 winShmLeaveMutex();
4503
dana1801312024-11-30 20:00:544504 /* Free the connection p */
4505 sqlite3_free(p);
4506 pDbFd->pShm = 0;
drh83235212010-05-14 16:34:344507 return SQLITE_OK;
4508}
4509
4510/*
shaneh1f3e27b2010-07-12 20:46:334511** Change the lock state for a shared-memory segment.
4512*/
4513static int winShmLock(
4514 sqlite3_file *fd, /* Database file holding the shared memory */
4515 int ofst, /* First lock to acquire or release */
4516 int n, /* Number of locks to acquire or release */
4517 int flags /* What to do with the lock */
4518){
4519 winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */
4520 winShm *p = pDbFd->pShm; /* The shared memory being locked */
drh56d88aa2022-03-22 19:41:554521 winShmNode *pShmNode;
shaneh1f3e27b2010-07-12 20:46:334522 int rc = SQLITE_OK; /* Result code */
dan362d51a2024-12-26 16:10:154523 u16 mask = (u16)((1U<<(ofst+n)) - (1U<<ofst)); /* Mask of locks to [un]take */
shaneh1f3e27b2010-07-12 20:46:334524
drh56d88aa2022-03-22 19:41:554525 if( p==0 ) return SQLITE_IOERR_SHMLOCK;
4526 pShmNode = p->pShmNode;
4527 if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK;
4528
shaneh1f3e27b2010-07-12 20:46:334529 assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
4530 assert( n>=1 );
4531 assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
4532 || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
4533 || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
4534 || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
4535 assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
4536
dan6bd3faa2024-11-22 21:24:084537 /* Check that, if this to be a blocking lock, no locks that occur later
4538 ** in the following list than the lock being obtained are already held:
4539 **
dan420233e2025-05-31 15:10:414540 ** 1. Recovery lock (ofst==2).
4541 ** 2. Checkpointer lock (ofst==1).
4542 ** 3. Write lock (ofst==0).
4543 ** 4. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
dan6bd3faa2024-11-22 21:24:084544 **
4545 ** In other words, if this is a blocking lock, none of the locks that
4546 ** occur later in the above list than the lock being obtained may be
4547 ** held.
dan6bd3faa2024-11-22 21:24:084548 */
dan833dd3d2025-02-11 18:29:354549#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && defined(SQLITE_DEBUG)
dan6bd3faa2024-11-22 21:24:084550 {
4551 u16 lockMask = (p->exclMask|p->sharedMask);
4552 assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
dan420233e2025-05-31 15:10:414553 (ofst!=2 || lockMask==0)
dan6bd3faa2024-11-22 21:24:084554 && (ofst!=1 || lockMask==0 || lockMask==2)
4555 && (ofst!=0 || lockMask<3)
4556 && (ofst<3 || lockMask<(1<<ofst))
4557 ));
shaneh1f3e27b2010-07-12 20:46:334558 }
dan6bd3faa2024-11-22 21:24:084559#endif
shaneh1f3e27b2010-07-12 20:46:334560
dan6bd3faa2024-11-22 21:24:084561 /* Check if there is any work to do. There are three cases:
4562 **
4563 ** a) An unlock operation where there are locks to unlock,
4564 ** b) An shared lock where the requested lock is not already held
4565 ** c) An exclusive lock where the requested lock is not already held
4566 **
4567 ** The SQLite core never requests an exclusive lock that it already holds.
dana1801312024-11-30 20:00:544568 ** This is assert()ed immediately below. */
dan6bd3faa2024-11-22 21:24:084569 assert( flags!=(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK)
4570 || 0==(p->exclMask & mask)
4571 );
4572 if( ((flags & SQLITE_SHM_UNLOCK) && ((p->exclMask|p->sharedMask) & mask))
4573 || (flags==(SQLITE_SHM_SHARED|SQLITE_SHM_LOCK) && 0==(p->sharedMask & mask))
4574 || (flags==(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK))
4575 ){
shaneh1f3e27b2010-07-12 20:46:334576
dana1801312024-11-30 20:00:544577 if( flags & SQLITE_SHM_UNLOCK ){
4578 /* Case (a) - unlock. */
shaneh1f3e27b2010-07-12 20:46:334579
dana1801312024-11-30 20:00:544580 assert( (p->exclMask & p->sharedMask)==0 );
4581 assert( !(flags & SQLITE_SHM_EXCLUSIVE) || (p->exclMask & mask)==mask );
4582 assert( !(flags & SQLITE_SHM_SHARED) || (p->sharedMask & mask)==mask );
shaneh1f3e27b2010-07-12 20:46:334583
dana1801312024-11-30 20:00:544584 rc = winHandleUnlock(p->hShm, ofst+WIN_SHM_BASE, n);
shaneh1f3e27b2010-07-12 20:46:334585
dana1801312024-11-30 20:00:544586 /* If successful, also clear the bits in sharedMask/exclMask */
shaneh1f3e27b2010-07-12 20:46:334587 if( rc==SQLITE_OK ){
dana1801312024-11-30 20:00:544588 p->exclMask = (p->exclMask & ~mask);
4589 p->sharedMask = (p->sharedMask & ~mask);
dan6bd3faa2024-11-22 21:24:084590 }
dana1801312024-11-30 20:00:544591 }else{
4592 int bExcl = ((flags & SQLITE_SHM_EXCLUSIVE) ? 1 : 0);
dan46288882025-01-30 15:26:164593 DWORD nMs = winFileBusyTimeout(pDbFd);
dand50eb9c2024-12-10 19:00:074594 rc = winHandleLockTimeout(p->hShm, ofst+WIN_SHM_BASE, n, bExcl, nMs);
dana1801312024-11-30 20:00:544595 if( rc==SQLITE_OK ){
4596 if( bExcl ){
4597 p->exclMask = (p->exclMask | mask);
4598 }else{
4599 p->sharedMask = (p->sharedMask | mask);
dan6bd3faa2024-11-22 21:24:084600 }
shaneh1f3e27b2010-07-12 20:46:334601 }
4602 }
4603 }
dan6bd3faa2024-11-22 21:24:084604
4605 OSTRACE((
dan362d51a2024-12-26 16:10:154606 "SHM-LOCK(%d,%d,%d) pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x,"
4607 " rc=%s\n",
4608 ofst, n, flags,
4609 osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask,
4610 sqlite3ErrName(rc))
4611 );
shaneh1f3e27b2010-07-12 20:46:334612 return rc;
4613}
4614
4615/*
mistachkin17835a52014-08-06 03:06:014616** Implement a memory barrier or memory fence on shared memory.
shaneh1f3e27b2010-07-12 20:46:334617**
4618** All loads and stores begun before the barrier must complete before
4619** any load or store begun after the barrier.
4620*/
4621static void winShmBarrier(
4622 sqlite3_file *fd /* Database holding the shared memory */
4623){
4624 UNUSED_PARAMETER(fd);
drh22c733d2015-09-24 12:40:434625 sqlite3MemoryBarrier(); /* compiler-defined memory barrier */
4626 winShmEnterMutex(); /* Also mutex, for redundancy */
shaneh1f3e27b2010-07-12 20:46:334627 winShmLeaveMutex();
4628}
4629
4630/*
mistachkin17835a52014-08-06 03:06:014631** This function is called to obtain a pointer to region iRegion of the
4632** shared-memory associated with the database file fd. Shared-memory regions
4633** are numbered starting from zero. Each shared-memory region is szRegion
dan9785fc92010-06-14 16:16:334634** bytes in size.
drh83235212010-05-14 16:34:344635**
dan9785fc92010-06-14 16:16:334636** If an error occurs, an error code is returned and *pp is set to NULL.
drh83235212010-05-14 16:34:344637**
dan9785fc92010-06-14 16:16:334638** Otherwise, if the isWrite parameter is 0 and the requested shared-memory
4639** region has not been allocated (by any client, including one running in a
mistachkin17835a52014-08-06 03:06:014640** separate process), then *pp is set to NULL and SQLITE_OK returned. If
4641** isWrite is non-zero and the requested shared-memory region has not yet
dan9785fc92010-06-14 16:16:334642** been allocated, it is allocated by this function.
4643**
4644** If the shared-memory region has already been allocated or is allocated by
mistachkin17835a52014-08-06 03:06:014645** this call as described above, then it is mapped into this processes
4646** address space (if it is not already), *pp is set to point to the mapped
dan9785fc92010-06-14 16:16:334647** memory and SQLITE_OK returned.
drh83235212010-05-14 16:34:344648*/
dan9785fc92010-06-14 16:16:334649static int winShmMap(
4650 sqlite3_file *fd, /* Handle open on database file */
4651 int iRegion, /* Region to retrieve */
4652 int szRegion, /* Size of regions */
4653 int isWrite, /* True to extend file if necessary */
4654 void volatile **pp /* OUT: Mapped memory */
drh83235212010-05-14 16:34:344655){
4656 winFile *pDbFd = (winFile*)fd;
mistachkindedc5ea2015-01-16 19:35:454657 winShm *pShm = pDbFd->pShm;
danda9fe0c2010-07-13 18:44:034658 winShmNode *pShmNode;
mistachkin4ff84312017-11-09 16:30:554659 DWORD protect = PAGE_READWRITE;
4660 DWORD flags = FILE_MAP_WRITE | FILE_MAP_READ;
drh83235212010-05-14 16:34:344661 int rc = SQLITE_OK;
4662
mistachkindedc5ea2015-01-16 19:35:454663 if( !pShm ){
danda9fe0c2010-07-13 18:44:034664 rc = winOpenSharedMemory(pDbFd);
4665 if( rc!=SQLITE_OK ) return rc;
mistachkindedc5ea2015-01-16 19:35:454666 pShm = pDbFd->pShm;
drh2cd02a52019-07-16 18:27:074667 assert( pShm!=0 );
danda9fe0c2010-07-13 18:44:034668 }
mistachkindedc5ea2015-01-16 19:35:454669 pShmNode = pShm->pShmNode;
danda9fe0c2010-07-13 18:44:034670
drh83235212010-05-14 16:34:344671 sqlite3_mutex_enter(pShmNode->mutex);
mistachkin4ff84312017-11-09 16:30:554672 if( pShmNode->isUnlocked ){
dana1801312024-11-30 20:00:544673 /* Take the DMS lock. */
4674 assert( pShmNode->nRegion==0 );
dand50eb9c2024-12-10 19:00:074675 rc = winLockSharedMemory(pShmNode, winFileBusyTimeout(pDbFd));
mistachkin4ff84312017-11-09 16:30:554676 if( rc!=SQLITE_OK ) goto shmpage_out;
mistachkin4ff84312017-11-09 16:30:554677 }
dan9785fc92010-06-14 16:16:334678
dana1801312024-11-30 20:00:544679 assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
dan9785fc92010-06-14 16:16:334680 if( pShmNode->nRegion<=iRegion ){
dana1801312024-11-30 20:00:544681 HANDLE hShared = pShmNode->hSharedShm;
dan9785fc92010-06-14 16:16:334682 struct ShmRegion *apNew; /* New aRegion[] array */
4683 int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
4684 sqlite3_int64 sz; /* Current size of wal-index file */
4685
4686 pShmNode->szRegion = szRegion;
4687
4688 /* The requested region is not mapped into this processes address space.
4689 ** Check to see if it has been allocated (i.e. if the wal-index file is
4690 ** large enough to contain the requested region).
4691 */
dana1801312024-11-30 20:00:544692 rc = winHandleSize(hShared, &sz);
dan9785fc92010-06-14 16:16:334693 if( rc!=SQLITE_OK ){
dana1801312024-11-30 20:00:544694 rc = winLogError(rc, osGetLastError(), "winShmMap1", pDbFd->zPath);
dan9785fc92010-06-14 16:16:334695 goto shmpage_out;
drh83235212010-05-14 16:34:344696 }
dan9785fc92010-06-14 16:16:334697
4698 if( sz<nByte ){
4699 /* The requested memory region does not exist. If isWrite is set to
4700 ** zero, exit early. *pp will be set to NULL and SQLITE_OK returned.
4701 **
4702 ** Alternatively, if isWrite is non-zero, use ftruncate() to allocate
dana1801312024-11-30 20:00:544703 ** the requested memory region. */
dan9785fc92010-06-14 16:16:334704 if( !isWrite ) goto shmpage_out;
dana1801312024-11-30 20:00:544705 rc = winHandleTruncate(hShared, nByte);
dan9785fc92010-06-14 16:16:334706 if( rc!=SQLITE_OK ){
dana1801312024-11-30 20:00:544707 rc = winLogError(rc, osGetLastError(), "winShmMap2", pDbFd->zPath);
dan9785fc92010-06-14 16:16:334708 goto shmpage_out;
4709 }
4710 }
4711
4712 /* Map the requested memory region into this processes address space. */
dana1801312024-11-30 20:00:544713 apNew = (struct ShmRegion*)sqlite3_realloc64(
dan9785fc92010-06-14 16:16:334714 pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
4715 );
4716 if( !apNew ){
mistachkinfad30392016-02-13 23:43:464717 rc = SQLITE_IOERR_NOMEM_BKPT;
dan9785fc92010-06-14 16:16:334718 goto shmpage_out;
4719 }
4720 pShmNode->aRegion = apNew;
4721
mistachkin4ff84312017-11-09 16:30:554722 if( pShmNode->isReadonly ){
4723 protect = PAGE_READONLY;
4724 flags = FILE_MAP_READ;
4725 }
4726
dan9785fc92010-06-14 16:16:334727 while( pShmNode->nRegion<=iRegion ){
mistachkinc60941f2012-09-13 01:51:024728 HANDLE hMap = NULL; /* file-mapping handle */
dan9785fc92010-06-14 16:16:334729 void *pMap = 0; /* Mapped memory region */
mistachkin17835a52014-08-06 03:06:014730
mistachkin1e6eea92012-05-31 22:12:264731#if SQLITE_OS_WINRT
dana1801312024-11-30 20:00:544732 hMap = osCreateFileMappingFromApp(hShared, NULL, protect, nByte, NULL);
mistachkinc60941f2012-09-13 01:51:024733#elif defined(SQLITE_WIN32_HAS_WIDE)
dana1801312024-11-30 20:00:544734 hMap = osCreateFileMappingW(hShared, NULL, protect, 0, nByte, NULL);
mistachkind5be6f02016-01-27 07:28:334735#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA
dana1801312024-11-30 20:00:544736 hMap = osCreateFileMappingA(hShared, NULL, protect, 0, nByte, NULL);
mistachkin1e6eea92012-05-31 22:12:264737#endif
dana1801312024-11-30 20:00:544738
mistachkine84d8d32013-04-29 03:09:104739 OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n",
4740 osGetCurrentProcessId(), pShmNode->nRegion, nByte,
shaneh420398c2010-09-03 04:29:304741 hMap ? "ok" : "failed"));
dan9785fc92010-06-14 16:16:334742 if( hMap ){
shaneh420398c2010-09-03 04:29:304743 int iOffset = pShmNode->nRegion*szRegion;
4744 int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
mistachkin287a48d2012-03-03 13:15:254745#if SQLITE_OS_WINRT
mistachkin4ff84312017-11-09 16:30:554746 pMap = osMapViewOfFileFromApp(hMap, flags,
mistachkin1e6eea92012-05-31 22:12:264747 iOffset - iOffsetShift, szRegion + iOffsetShift
mistachkin287a48d2012-03-03 13:15:254748 );
4749#else
mistachkin4ff84312017-11-09 16:30:554750 pMap = osMapViewOfFile(hMap, flags,
shaneh420398c2010-09-03 04:29:304751 0, iOffset - iOffsetShift, szRegion + iOffsetShift
dan9785fc92010-06-14 16:16:334752 );
mistachkin287a48d2012-03-03 13:15:254753#endif
mistachkine84d8d32013-04-29 03:09:104754 OSTRACE(("SHM-MAP-MAP pid=%lu, region=%d, offset=%d, size=%d, rc=%s\n",
4755 osGetCurrentProcessId(), pShmNode->nRegion, iOffset,
mistachkin318507b2011-11-11 22:08:544756 szRegion, pMap ? "ok" : "failed"));
dan9785fc92010-06-14 16:16:334757 }
4758 if( !pMap ){
mistachkin318507b2011-11-11 22:08:544759 pShmNode->lastErrno = osGetLastError();
mistachkin2aef9972011-11-10 20:21:204760 rc = winLogError(SQLITE_IOERR_SHMMAP, pShmNode->lastErrno,
mistachkin9f11ef12013-08-31 02:48:564761 "winShmMap3", pDbFd->zPath);
mistachkin318507b2011-11-11 22:08:544762 if( hMap ) osCloseHandle(hMap);
dan9785fc92010-06-14 16:16:334763 goto shmpage_out;
drh83235212010-05-14 16:34:344764 }
dan9785fc92010-06-14 16:16:334765
4766 pShmNode->aRegion[pShmNode->nRegion].pMap = pMap;
4767 pShmNode->aRegion[pShmNode->nRegion].hMap = hMap;
4768 pShmNode->nRegion++;
drh83235212010-05-14 16:34:344769 }
4770 }
dan9785fc92010-06-14 16:16:334771
4772shmpage_out:
4773 if( pShmNode->nRegion>iRegion ){
shaneh420398c2010-09-03 04:29:304774 int iOffset = iRegion*szRegion;
4775 int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
dan9785fc92010-06-14 16:16:334776 char *p = (char *)pShmNode->aRegion[iRegion].pMap;
shaneh420398c2010-09-03 04:29:304777 *pp = (void *)&p[iOffsetShift];
dan9785fc92010-06-14 16:16:334778 }else{
4779 *pp = 0;
4780 }
dana1801312024-11-30 20:00:544781 if( pShmNode->isReadonly && rc==SQLITE_OK ){
4782 rc = SQLITE_READONLY;
4783 }
drh83235212010-05-14 16:34:344784 sqlite3_mutex_leave(pShmNode->mutex);
4785 return rc;
4786}
4787
drh83235212010-05-14 16:34:344788#else
shaneh1f3e27b2010-07-12 20:46:334789# define winShmMap 0
danda9fe0c2010-07-13 18:44:034790# define winShmLock 0
drh286a2882010-05-20 23:51:064791# define winShmBarrier 0
drhe11fedc2010-07-14 00:14:304792# define winShmUnmap 0
drh83235212010-05-14 16:34:344793#endif /* #ifndef SQLITE_OMIT_WAL */
shaneh1f3e27b2010-07-12 20:46:334794
drh83235212010-05-14 16:34:344795/*
mistachkindaf9a5a2013-03-23 09:56:394796** Cleans up the mapped region of the specified file, if any.
4797*/
mistachkin5824e052013-04-15 20:08:274798#if SQLITE_MAX_MMAP_SIZE>0
drh5175b322013-04-01 17:22:514799static int winUnmapfile(winFile *pFile){
mistachkindaf9a5a2013-03-23 09:56:394800 assert( pFile!=0 );
mistachkine84d8d32013-04-29 03:09:104801 OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, pMapRegion=%p, "
drh48ea97e2018-11-24 16:07:214802 "mmapSize=%lld, mmapSizeMax=%lld\n",
mistachkine84d8d32013-04-29 03:09:104803 osGetCurrentProcessId(), pFile, pFile->hMap, pFile->pMapRegion,
drh48ea97e2018-11-24 16:07:214804 pFile->mmapSize, pFile->mmapSizeMax));
mistachkindaf9a5a2013-03-23 09:56:394805 if( pFile->pMapRegion ){
4806 if( !osUnmapViewOfFile(pFile->pMapRegion) ){
4807 pFile->lastErrno = osGetLastError();
mistachkine84d8d32013-04-29 03:09:104808 OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, pMapRegion=%p, "
4809 "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(), pFile,
4810 pFile->pMapRegion));
drh5175b322013-04-01 17:22:514811 return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
mistachkin9f11ef12013-08-31 02:48:564812 "winUnmapfile1", pFile->zPath);
mistachkindaf9a5a2013-03-23 09:56:394813 }
4814 pFile->pMapRegion = 0;
4815 pFile->mmapSize = 0;
4816 }
4817 if( pFile->hMap!=NULL ){
4818 if( !osCloseHandle(pFile->hMap) ){
4819 pFile->lastErrno = osGetLastError();
mistachkine84d8d32013-04-29 03:09:104820 OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, rc=SQLITE_IOERR_MMAP\n",
4821 osGetCurrentProcessId(), pFile, pFile->hMap));
drh5175b322013-04-01 17:22:514822 return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
mistachkin9f11ef12013-08-31 02:48:564823 "winUnmapfile2", pFile->zPath);
mistachkindaf9a5a2013-03-23 09:56:394824 }
4825 pFile->hMap = NULL;
4826 }
mistachkine84d8d32013-04-29 03:09:104827 OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
4828 osGetCurrentProcessId(), pFile));
mistachkindaf9a5a2013-03-23 09:56:394829 return SQLITE_OK;
4830}
4831
4832/*
drh5175b322013-04-01 17:22:514833** Memory map or remap the file opened by file-descriptor pFd (if the file
mistachkin17835a52014-08-06 03:06:014834** is already mapped, the existing mapping is replaced by the new). Or, if
4835** there already exists a mapping for this file, and there are still
drh5175b322013-04-01 17:22:514836** outstanding xFetch() references to it, this function is a no-op.
4837**
mistachkin17835a52014-08-06 03:06:014838** If parameter nByte is non-negative, then it is the requested size of
4839** the mapping to create. Otherwise, if nByte is less than zero, then the
drh5175b322013-04-01 17:22:514840** requested size is the size of the file on disk. The actual size of the
mistachkin17835a52014-08-06 03:06:014841** created mapping is either the requested size or the value configured
drh9b4c59f2013-04-15 17:03:424842** using SQLITE_FCNTL_MMAP_SIZE, whichever is smaller.
drh5175b322013-04-01 17:22:514843**
4844** SQLITE_OK is returned if no error occurs (even if the mapping is not
4845** recreated as a result of outstanding references) or an SQLite error
4846** code otherwise.
mistachkindaf9a5a2013-03-23 09:56:394847*/
drh5175b322013-04-01 17:22:514848static int winMapfile(winFile *pFd, sqlite3_int64 nByte){
4849 sqlite3_int64 nMap = nByte;
4850 int rc;
mistachkindaf9a5a2013-03-23 09:56:394851
drh5175b322013-04-01 17:22:514852 assert( nMap>=0 || pFd->nFetchOut==0 );
mistachkine84d8d32013-04-29 03:09:104853 OSTRACE(("MAP-FILE pid=%lu, pFile=%p, size=%lld\n",
4854 osGetCurrentProcessId(), pFd, nByte));
mistachkinf2c1c992013-04-28 01:44:434855
drh5175b322013-04-01 17:22:514856 if( pFd->nFetchOut>0 ) return SQLITE_OK;
mistachkindaf9a5a2013-03-23 09:56:394857
drh5175b322013-04-01 17:22:514858 if( nMap<0 ){
4859 rc = winFileSize((sqlite3_file*)pFd, &nMap);
4860 if( rc ){
mistachkine84d8d32013-04-29 03:09:104861 OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_IOERR_FSTAT\n",
4862 osGetCurrentProcessId(), pFd));
drh5175b322013-04-01 17:22:514863 return SQLITE_IOERR_FSTAT;
mistachkindaf9a5a2013-03-23 09:56:394864 }
mistachkindaf9a5a2013-03-23 09:56:394865 }
drh9b4c59f2013-04-15 17:03:424866 if( nMap>pFd->mmapSizeMax ){
4867 nMap = pFd->mmapSizeMax;
drh5175b322013-04-01 17:22:514868 }
drhdb56bcb2013-04-01 18:15:504869 nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1);
mistachkin17835a52014-08-06 03:06:014870
drh5175b322013-04-01 17:22:514871 if( nMap==0 && pFd->mmapSize>0 ){
4872 winUnmapfile(pFd);
4873 }
4874 if( nMap!=pFd->mmapSize ){
4875 void *pNew = 0;
mistachkindaf9a5a2013-03-23 09:56:394876 DWORD protect = PAGE_READONLY;
4877 DWORD flags = FILE_MAP_READ;
drh5175b322013-04-01 17:22:514878
4879 winUnmapfile(pFd);
mistachkinc88cd132015-11-17 21:42:324880#ifdef SQLITE_MMAP_READWRITE
drh5175b322013-04-01 17:22:514881 if( (pFd->ctrlFlags & WINFILE_RDONLY)==0 ){
mistachkindaf9a5a2013-03-23 09:56:394882 protect = PAGE_READWRITE;
4883 flags |= FILE_MAP_WRITE;
4884 }
mistachkinc88cd132015-11-17 21:42:324885#endif
mistachkindaf9a5a2013-03-23 09:56:394886#if SQLITE_OS_WINRT
drhf9d18e42013-04-01 17:56:284887 pFd->hMap = osCreateFileMappingFromApp(pFd->h, NULL, protect, nMap, NULL);
mistachkindaf9a5a2013-03-23 09:56:394888#elif defined(SQLITE_WIN32_HAS_WIDE)
drhf9d18e42013-04-01 17:56:284889 pFd->hMap = osCreateFileMappingW(pFd->h, NULL, protect,
drh5175b322013-04-01 17:22:514890 (DWORD)((nMap>>32) & 0xffffffff),
4891 (DWORD)(nMap & 0xffffffff), NULL);
mistachkind5be6f02016-01-27 07:28:334892#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA
drhf9d18e42013-04-01 17:56:284893 pFd->hMap = osCreateFileMappingA(pFd->h, NULL, protect,
drh5175b322013-04-01 17:22:514894 (DWORD)((nMap>>32) & 0xffffffff),
4895 (DWORD)(nMap & 0xffffffff), NULL);
mistachkindaf9a5a2013-03-23 09:56:394896#endif
drhf9d18e42013-04-01 17:56:284897 if( pFd->hMap==NULL ){
drh5175b322013-04-01 17:22:514898 pFd->lastErrno = osGetLastError();
4899 rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno,
mistachkin9f11ef12013-08-31 02:48:564900 "winMapfile1", pFd->zPath);
drh5175b322013-04-01 17:22:514901 /* Log the error, but continue normal operation using xRead/xWrite */
mistachkin9f11ef12013-08-31 02:48:564902 OSTRACE(("MAP-FILE-CREATE pid=%lu, pFile=%p, rc=%s\n",
4903 osGetCurrentProcessId(), pFd, sqlite3ErrName(rc)));
drh5175b322013-04-01 17:22:514904 return SQLITE_OK;
mistachkindaf9a5a2013-03-23 09:56:394905 }
drh07fa8642013-04-02 14:37:404906 assert( (nMap % winSysInfo.dwPageSize)==0 );
mistachkina9d79ae2013-04-02 20:13:044907 assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff );
mistachkinc6fc65c2013-07-31 23:28:364908#if SQLITE_OS_WINRT
4909 pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, (SIZE_T)nMap);
4910#else
drhf9d18e42013-04-01 17:56:284911 pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap);
mistachkindaf9a5a2013-03-23 09:56:394912#endif
4913 if( pNew==NULL ){
drhf9d18e42013-04-01 17:56:284914 osCloseHandle(pFd->hMap);
4915 pFd->hMap = NULL;
drh5175b322013-04-01 17:22:514916 pFd->lastErrno = osGetLastError();
mistachkin9f11ef12013-08-31 02:48:564917 rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno,
4918 "winMapfile2", pFd->zPath);
4919 /* Log the error, but continue normal operation using xRead/xWrite */
4920 OSTRACE(("MAP-FILE-MAP pid=%lu, pFile=%p, rc=%s\n",
4921 osGetCurrentProcessId(), pFd, sqlite3ErrName(rc)));
drh5175b322013-04-01 17:22:514922 return SQLITE_OK;
mistachkindaf9a5a2013-03-23 09:56:394923 }
drh5175b322013-04-01 17:22:514924 pFd->pMapRegion = pNew;
4925 pFd->mmapSize = nMap;
mistachkindaf9a5a2013-03-23 09:56:394926 }
4927
mistachkine84d8d32013-04-29 03:09:104928 OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
4929 osGetCurrentProcessId(), pFd));
drh5175b322013-04-01 17:22:514930 return SQLITE_OK;
4931}
drh9b4c59f2013-04-15 17:03:424932#endif /* SQLITE_MAX_MMAP_SIZE>0 */
mistachkindaf9a5a2013-03-23 09:56:394933
drh5175b322013-04-01 17:22:514934/*
4935** If possible, return a pointer to a mapping of file fd starting at offset
4936** iOff. The mapping must be valid for at least nAmt bytes.
4937**
4938** If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
4939** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
4940** Finally, if an error does occur, return an SQLite error code. The final
4941** value of *pp is undefined in this case.
4942**
mistachkin17835a52014-08-06 03:06:014943** If this function does return a pointer, the caller must eventually
mistachkine84d8d32013-04-29 03:09:104944** release the reference by calling winUnfetch().
drh5175b322013-04-01 17:22:514945*/
4946static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
mistachkin5824e052013-04-15 20:08:274947#if SQLITE_MAX_MMAP_SIZE>0
drh5175b322013-04-01 17:22:514948 winFile *pFd = (winFile*)fd; /* The underlying database file */
mistachkin5824e052013-04-15 20:08:274949#endif
drh5175b322013-04-01 17:22:514950 *pp = 0;
4951
mistachkine84d8d32013-04-29 03:09:104952 OSTRACE(("FETCH pid=%lu, pFile=%p, offset=%lld, amount=%d, pp=%p\n",
4953 osGetCurrentProcessId(), fd, iOff, nAmt, pp));
mistachkinf2c1c992013-04-28 01:44:434954
drh9b4c59f2013-04-15 17:03:424955#if SQLITE_MAX_MMAP_SIZE>0
4956 if( pFd->mmapSizeMax>0 ){
danbcf3df02024-01-23 16:09:224957 /* Ensure that there is always at least a 256 byte buffer of addressable
4958 ** memory following the returned page. If the database is corrupt,
4959 ** SQLite may overread the page slightly (in practice only a few bytes,
4960 ** but 256 is safe, round, number). */
4961 const int nEofBuffer = 256;
drh5175b322013-04-01 17:22:514962 if( pFd->pMapRegion==0 ){
4963 int rc = winMapfile(pFd, -1);
mistachkinf2c1c992013-04-28 01:44:434964 if( rc!=SQLITE_OK ){
mistachkine84d8d32013-04-29 03:09:104965 OSTRACE(("FETCH pid=%lu, pFile=%p, rc=%s\n",
4966 osGetCurrentProcessId(), pFd, sqlite3ErrName(rc)));
mistachkinf2c1c992013-04-28 01:44:434967 return rc;
4968 }
drh5175b322013-04-01 17:22:514969 }
danbcf3df02024-01-23 16:09:224970 if( pFd->mmapSize >= (iOff+nAmt+nEofBuffer) ){
drh2cd02a52019-07-16 18:27:074971 assert( pFd->pMapRegion!=0 );
drh5175b322013-04-01 17:22:514972 *pp = &((u8 *)pFd->pMapRegion)[iOff];
4973 pFd->nFetchOut++;
4974 }
4975 }
drh6e0b6d52013-04-09 16:19:204976#endif
mistachkinf2c1c992013-04-28 01:44:434977
mistachkine84d8d32013-04-29 03:09:104978 OSTRACE(("FETCH pid=%lu, pFile=%p, pp=%p, *pp=%p, rc=SQLITE_OK\n",
4979 osGetCurrentProcessId(), fd, pp, *pp));
drh5175b322013-04-01 17:22:514980 return SQLITE_OK;
4981}
4982
4983/*
mistachkin17835a52014-08-06 03:06:014984** If the third argument is non-NULL, then this function releases a
mistachkine84d8d32013-04-29 03:09:104985** reference obtained by an earlier call to winFetch(). The second
drh5175b322013-04-01 17:22:514986** argument passed to this function must be the same as the corresponding
mistachkin17835a52014-08-06 03:06:014987** argument that was passed to the winFetch() invocation.
drh5175b322013-04-01 17:22:514988**
mistachkin17835a52014-08-06 03:06:014989** Or, if the third argument is NULL, then this function is being called
4990** to inform the VFS layer that, according to POSIX, any existing mapping
drh5175b322013-04-01 17:22:514991** may now be invalid and should be unmapped.
4992*/
4993static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){
mistachkin5824e052013-04-15 20:08:274994#if SQLITE_MAX_MMAP_SIZE>0
drh5175b322013-04-01 17:22:514995 winFile *pFd = (winFile*)fd; /* The underlying database file */
4996
mistachkin17835a52014-08-06 03:06:014997 /* If p==0 (unmap the entire file) then there must be no outstanding
drh5175b322013-04-01 17:22:514998 ** xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
4999 ** then there must be at least one outstanding. */
5000 assert( (p==0)==(pFd->nFetchOut==0) );
5001
5002 /* If p!=0, it must match the iOff value. */
5003 assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] );
5004
mistachkine84d8d32013-04-29 03:09:105005 OSTRACE(("UNFETCH pid=%lu, pFile=%p, offset=%lld, p=%p\n",
5006 osGetCurrentProcessId(), pFd, iOff, p));
mistachkinf2c1c992013-04-28 01:44:435007
drh5175b322013-04-01 17:22:515008 if( p ){
5009 pFd->nFetchOut--;
5010 }else{
drha539c8a2013-04-01 18:25:485011 /* FIXME: If Windows truly always prevents truncating or deleting a
5012 ** file while a mapping is held, then the following winUnmapfile() call
peter.d.reid60ec9142014-09-06 16:39:465013 ** is unnecessary can be omitted - potentially improving
drha539c8a2013-04-01 18:25:485014 ** performance. */
drh5175b322013-04-01 17:22:515015 winUnmapfile(pFd);
5016 }
5017
5018 assert( pFd->nFetchOut>=0 );
mistachkin5824e052013-04-15 20:08:275019#endif
mistachkinf2c1c992013-04-28 01:44:435020
mistachkine84d8d32013-04-29 03:09:105021 OSTRACE(("UNFETCH pid=%lu, pFile=%p, rc=SQLITE_OK\n",
5022 osGetCurrentProcessId(), fd));
drh5175b322013-04-01 17:22:515023 return SQLITE_OK;
mistachkindaf9a5a2013-03-23 09:56:395024}
5025
5026/*
shaneh1f3e27b2010-07-12 20:46:335027** Here ends the implementation of all sqlite3_file methods.
5028**
5029********************** End sqlite3_file Methods *******************************
5030******************************************************************************/
drh83235212010-05-14 16:34:345031
drh153c62c2007-08-24 03:51:335032/*
5033** This vector defines all the methods that can operate on an
5034** sqlite3_file for win32.
5035*/
5036static const sqlite3_io_methods winIoMethod = {
mistachkindaf9a5a2013-03-23 09:56:395037 3, /* iVersion */
danda9fe0c2010-07-13 18:44:035038 winClose, /* xClose */
5039 winRead, /* xRead */
5040 winWrite, /* xWrite */
5041 winTruncate, /* xTruncate */
5042 winSync, /* xSync */
5043 winFileSize, /* xFileSize */
5044 winLock, /* xLock */
5045 winUnlock, /* xUnlock */
5046 winCheckReservedLock, /* xCheckReservedLock */
5047 winFileControl, /* xFileControl */
5048 winSectorSize, /* xSectorSize */
5049 winDeviceCharacteristics, /* xDeviceCharacteristics */
5050 winShmMap, /* xShmMap */
5051 winShmLock, /* xShmLock */
5052 winShmBarrier, /* xShmBarrier */
mistachkindaf9a5a2013-03-23 09:56:395053 winShmUnmap, /* xShmUnmap */
drh5175b322013-04-01 17:22:515054 winFetch, /* xFetch */
5055 winUnfetch /* xUnfetch */
drh9c06c952005-11-26 00:25:005056};
5057
mistachkin1e754832016-07-08 21:14:375058/*
5059** This vector defines all the methods that can operate on an
5060** sqlite3_file for win32 without performing any locking.
5061*/
5062static const sqlite3_io_methods winIoNolockMethod = {
5063 3, /* iVersion */
5064 winClose, /* xClose */
5065 winRead, /* xRead */
5066 winWrite, /* xWrite */
5067 winTruncate, /* xTruncate */
5068 winSync, /* xSync */
5069 winFileSize, /* xFileSize */
5070 winNolockLock, /* xLock */
5071 winNolockUnlock, /* xUnlock */
5072 winNolockCheckReservedLock, /* xCheckReservedLock */
5073 winFileControl, /* xFileControl */
5074 winSectorSize, /* xSectorSize */
5075 winDeviceCharacteristics, /* xDeviceCharacteristics */
5076 winShmMap, /* xShmMap */
5077 winShmLock, /* xShmLock */
5078 winShmBarrier, /* xShmBarrier */
5079 winShmUnmap, /* xShmUnmap */
5080 winFetch, /* xFetch */
5081 winUnfetch /* xUnfetch */
5082};
5083
5084static winVfsAppData winAppData = {
5085 &winIoMethod, /* pMethod */
5086 0, /* pAppData */
5087 0 /* bNoLock */
5088};
5089
5090static winVfsAppData winNolockAppData = {
5091 &winIoNolockMethod, /* pMethod */
5092 0, /* pAppData */
5093 1 /* bNoLock */
5094};
5095
shaneh1f3e27b2010-07-12 20:46:335096/****************************************************************************
5097**************************** sqlite3_vfs methods ****************************
drh153c62c2007-08-24 03:51:335098**
shaneh1f3e27b2010-07-12 20:46:335099** This division contains the implementation of methods on the
5100** sqlite3_vfs object.
5101*/
drh153c62c2007-08-24 03:51:335102
drh054889e2005-11-30 03:20:315103/*
mistachkin37418272013-08-28 05:49:395104** This function returns non-zero if the specified UTF-8 string buffer
mistachkin14eca4e2013-11-07 22:11:555105** ends with a directory separator character or one was successfully
5106** added to it.
danielk197717b90b52008-06-06 11:11:255107*/
mistachkin14eca4e2013-11-07 22:11:555108static int winMakeEndInDirSep(int nBuf, char *zBuf){
mistachkin37418272013-08-28 05:49:395109 if( zBuf ){
5110 int nLen = sqlite3Strlen30(zBuf);
mistachkin14eca4e2013-11-07 22:11:555111 if( nLen>0 ){
5112 if( winIsDirSep(zBuf[nLen-1]) ){
5113 return 1;
5114 }else if( nLen+1<nBuf ){
stephan42e5ceb2025-03-10 15:15:135115 if( !osGetenv ){
5116 zBuf[nLen] = winGetDirSep();
5117 }else if( winIsDriveLetterAndColon(zBuf) && winIsDirSep(zBuf[2]) ){
5118 zBuf[nLen] = '\\';
5119 zBuf[2]='\\';
5120 }else{
5121 zBuf[nLen] = '/';
5122 }
mistachkin14eca4e2013-11-07 22:11:555123 zBuf[nLen+1] = '\0';
5124 return 1;
5125 }
5126 }
mistachkin37418272013-08-28 05:49:395127 }
5128 return 0;
5129}
5130
5131/*
drhe38b6e02022-11-07 15:01:055132** If sqlite3_temp_directory is defined, take the mutex and return true.
drh18a3a482022-09-02 00:36:165133**
drhe38b6e02022-11-07 15:01:055134** If sqlite3_temp_directory is NULL (undefined), omit the mutex and
5135** return false.
drh18a3a482022-09-02 00:36:165136*/
5137static int winTempDirDefined(void){
5138 sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
5139 if( sqlite3_temp_directory!=0 ) return 1;
5140 sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
5141 return 0;
5142}
5143
5144/*
mistachkin37418272013-08-28 05:49:395145** Create a temporary file name and store the resulting pointer into pzBuf.
5146** The pointer returned in pzBuf must be freed via sqlite3_free().
5147*/
5148static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
stephan42e5ceb2025-03-10 15:15:135149 static const char zChars[] =
danielk197717b90b52008-06-06 11:11:255150 "abcdefghijklmnopqrstuvwxyz"
5151 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
5152 "0123456789";
shane3582c5a2008-07-31 01:34:345153 size_t i, j;
drh7309b502023-08-16 15:10:075154 DWORD pid;
mistachkinfd4b90b2013-11-09 21:10:475155 int nPre = sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX);
drhef86b942025-02-17 17:33:145156 i64 nMax, nBuf, nDir, nLen;
mistachkin37418272013-08-28 05:49:395157 char *zBuf;
shanehe2ad9312010-07-08 03:13:335158
5159 /* It's odd to simulate an io-error here, but really this is just
5160 ** using the io-error infrastructure to test that SQLite handles this
mistachkin17835a52014-08-06 03:06:015161 ** function failing.
shanehe2ad9312010-07-08 03:13:335162 */
5163 SimulateIOError( return SQLITE_IOERR );
5164
mistachkin37418272013-08-28 05:49:395165 /* Allocate a temporary buffer to store the fully qualified file
5166 ** name for the temporary file. If this fails, we cannot continue.
5167 */
drhef86b942025-02-17 17:33:145168 nMax = pVfs->mxPathname;
5169 nBuf = 2 + (i64)nMax;
mistachkinfd4b90b2013-11-09 21:10:475170 zBuf = sqlite3MallocZero( nBuf );
mistachkin37418272013-08-28 05:49:395171 if( !zBuf ){
5172 OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
mistachkinfad30392016-02-13 23:43:465173 return SQLITE_IOERR_NOMEM_BKPT;
mistachkinc5484652012-03-05 22:52:335174 }
mistachkin37418272013-08-28 05:49:395175
5176 /* Figure out the effective temporary directory. First, check if one
5177 ** has been explicitly set by the application; otherwise, use the one
5178 ** configured by the operating system.
5179 */
mistachkinfd4b90b2013-11-09 21:10:475180 nDir = nMax - (nPre + 15);
5181 assert( nDir>0 );
drh18a3a482022-09-02 00:36:165182 if( winTempDirDefined() ){
mistachkinfd4b90b2013-11-09 21:10:475183 int nDirLen = sqlite3Strlen30(sqlite3_temp_directory);
5184 if( nDirLen>0 ){
5185 if( !winIsDirSep(sqlite3_temp_directory[nDirLen-1]) ){
5186 nDirLen++;
5187 }
5188 if( nDirLen>nDir ){
drh18a3a482022-09-02 00:36:165189 sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
mistachkinfd4b90b2013-11-09 21:10:475190 sqlite3_free(zBuf);
5191 OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
5192 return winLogError(SQLITE_ERROR, 0, "winGetTempname1", 0);
5193 }
5194 sqlite3_snprintf(nMax, zBuf, "%s", sqlite3_temp_directory);
5195 }
drh18a3a482022-09-02 00:36:165196 sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
mistachkinc5484652012-03-05 22:52:335197 }
drh18a3a482022-09-02 00:36:165198
stephan42e5ceb2025-03-10 15:15:135199#if defined(__CYGWIN__)
5200 else if( osGetenv!=NULL ){
mistachkind95a3d32013-08-30 21:52:385201 static const char *azDirs[] = {
5202 0, /* getenv("SQLITE_TMPDIR") */
5203 0, /* getenv("TMPDIR") */
5204 0, /* getenv("TMP") */
5205 0, /* getenv("TEMP") */
5206 0, /* getenv("USERPROFILE") */
5207 "/var/tmp",
5208 "/usr/tmp",
5209 "/tmp",
mistachkin1a88b142013-08-31 18:06:525210 ".",
mistachkind95a3d32013-08-30 21:52:385211 0 /* List terminator */
5212 };
5213 unsigned int i;
5214 const char *zDir = 0;
5215
stephan7b9407a2025-03-07 06:54:045216 if( !azDirs[0] ) azDirs[0] = osGetenv("SQLITE_TMPDIR");
5217 if( !azDirs[1] ) azDirs[1] = osGetenv("TMPDIR");
5218 if( !azDirs[2] ) azDirs[2] = osGetenv("TMP");
5219 if( !azDirs[3] ) azDirs[3] = osGetenv("TEMP");
5220 if( !azDirs[4] ) azDirs[4] = osGetenv("USERPROFILE");
mistachkind95a3d32013-08-30 21:52:385221 for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
5222 void *zConverted;
5223 if( zDir==0 ) continue;
5224 /* If the path starts with a drive letter followed by the colon
5225 ** character, assume it is already a native Win32 path; otherwise,
mistachkin14eca4e2013-11-07 22:11:555226 ** it must be converted to a native Win32 path via the Cygwin API
5227 ** prior to using it.
mistachkind95a3d32013-08-30 21:52:385228 */
stephan42e5ceb2025-03-10 15:15:135229 {
mistachkind95a3d32013-08-30 21:52:385230 zConverted = winConvertFromUtf8Filename(zDir);
5231 if( !zConverted ){
mistachkinc2165662013-10-16 09:49:105232 sqlite3_free(zBuf);
mistachkind95a3d32013-08-30 21:52:385233 OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
mistachkinfad30392016-02-13 23:43:465234 return SQLITE_IOERR_NOMEM_BKPT;
mistachkind95a3d32013-08-30 21:52:385235 }
5236 if( winIsDir(zConverted) ){
mistachkinfd4b90b2013-11-09 21:10:475237 sqlite3_snprintf(nMax, zBuf, "%s", zDir);
mistachkind95a3d32013-08-30 21:52:385238 sqlite3_free(zConverted);
5239 break;
5240 }
5241 sqlite3_free(zConverted);
mistachkind95a3d32013-08-30 21:52:385242 }
mistachkind95a3d32013-08-30 21:52:385243 }
5244 }
stephan42e5ceb2025-03-10 15:15:135245#endif
5246
5247#if !SQLITE_OS_WINRT && defined(_WIN32)
mistachkinb324bc72013-08-28 02:37:295248 else if( osIsNT() ){
danielk197717b90b52008-06-06 11:11:255249 char *zMulti;
mistachkinfd4b90b2013-11-09 21:10:475250 LPWSTR zWidePath = sqlite3MallocZero( nMax*sizeof(WCHAR) );
mistachkin37418272013-08-28 05:49:395251 if( !zWidePath ){
5252 sqlite3_free(zBuf);
5253 OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
mistachkinfad30392016-02-13 23:43:465254 return SQLITE_IOERR_NOMEM_BKPT;
mistachkin37418272013-08-28 05:49:395255 }
mistachkinfd4b90b2013-11-09 21:10:475256 if( osGetTempPathW(nMax, zWidePath)==0 ){
mistachkin37418272013-08-28 05:49:395257 sqlite3_free(zWidePath);
5258 sqlite3_free(zBuf);
mistachkin16a2e7a2013-07-31 22:27:165259 OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_GETTEMPPATH\n"));
mistachkin9f11ef12013-08-31 02:48:565260 return winLogError(SQLITE_IOERR_GETTEMPPATH, osGetLastError(),
mistachkinfd4b90b2013-11-09 21:10:475261 "winGetTempname2", 0);
mistachkin16a2e7a2013-07-31 22:27:165262 }
mistachkinb324bc72013-08-28 02:37:295263 zMulti = winUnicodeToUtf8(zWidePath);
danielk197717b90b52008-06-06 11:11:255264 if( zMulti ){
mistachkinfd4b90b2013-11-09 21:10:475265 sqlite3_snprintf(nMax, zBuf, "%s", zMulti);
mistachkin5f075382011-11-11 23:31:045266 sqlite3_free(zMulti);
mistachkin37418272013-08-28 05:49:395267 sqlite3_free(zWidePath);
danielk197717b90b52008-06-06 11:11:255268 }else{
mistachkin37418272013-08-28 05:49:395269 sqlite3_free(zWidePath);
5270 sqlite3_free(zBuf);
mistachkinf2c1c992013-04-28 01:44:435271 OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
mistachkinfad30392016-02-13 23:43:465272 return SQLITE_IOERR_NOMEM_BKPT;
danielk197717b90b52008-06-06 11:11:255273 }
drhd52ee722012-03-02 00:00:475274 }
5275#ifdef SQLITE_WIN32_HAS_ANSI
5276 else{
danielk197717b90b52008-06-06 11:11:255277 char *zUtf8;
mistachkinfd4b90b2013-11-09 21:10:475278 char *zMbcsPath = sqlite3MallocZero( nMax );
mistachkin37418272013-08-28 05:49:395279 if( !zMbcsPath ){
5280 sqlite3_free(zBuf);
5281 OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
mistachkinfad30392016-02-13 23:43:465282 return SQLITE_IOERR_NOMEM_BKPT;
mistachkin37418272013-08-28 05:49:395283 }
mistachkinfd4b90b2013-11-09 21:10:475284 if( osGetTempPathA(nMax, zMbcsPath)==0 ){
mistachkin37418272013-08-28 05:49:395285 sqlite3_free(zBuf);
mistachkin16a2e7a2013-07-31 22:27:165286 OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_GETTEMPPATH\n"));
mistachkin9f11ef12013-08-31 02:48:565287 return winLogError(SQLITE_IOERR_GETTEMPPATH, osGetLastError(),
mistachkinfd4b90b2013-11-09 21:10:475288 "winGetTempname3", 0);
mistachkin16a2e7a2013-07-31 22:27:165289 }
mistachkin12931202016-04-04 02:05:465290 zUtf8 = winMbcsToUtf8(zMbcsPath, osAreFileApisANSI());
danielk197717b90b52008-06-06 11:11:255291 if( zUtf8 ){
mistachkinfd4b90b2013-11-09 21:10:475292 sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
mistachkin5f075382011-11-11 23:31:045293 sqlite3_free(zUtf8);
danielk197717b90b52008-06-06 11:11:255294 }else{
mistachkin37418272013-08-28 05:49:395295 sqlite3_free(zBuf);
mistachkinf2c1c992013-04-28 01:44:435296 OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
mistachkinfad30392016-02-13 23:43:465297 return SQLITE_IOERR_NOMEM_BKPT;
danielk197717b90b52008-06-06 11:11:255298 }
5299 }
mistachkinc6fc65c2013-07-31 23:28:365300#endif /* SQLITE_WIN32_HAS_ANSI */
mistachkinc6fc65c2013-07-31 23:28:365301#endif /* !SQLITE_OS_WINRT */
shanehe2ad9312010-07-08 03:13:335302
mistachkinfd4b90b2013-11-09 21:10:475303 /*
5304 ** Check to make sure the temporary directory ends with an appropriate
5305 ** separator. If it does not and there is not enough space left to add
5306 ** one, fail.
shanehe2ad9312010-07-08 03:13:335307 */
mistachkinfd4b90b2013-11-09 21:10:475308 if( !winMakeEndInDirSep(nDir+1, zBuf) ){
mistachkin37418272013-08-28 05:49:395309 sqlite3_free(zBuf);
mistachkinf2c1c992013-04-28 01:44:435310 OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
mistachkinfd4b90b2013-11-09 21:10:475311 return winLogError(SQLITE_ERROR, 0, "winGetTempname4", 0);
shanehe2ad9312010-07-08 03:13:335312 }
5313
mistachkinfd4b90b2013-11-09 21:10:475314 /*
mistachkin17835a52014-08-06 03:06:015315 ** Check that the output buffer is large enough for the temporary file
mistachkinfd4b90b2013-11-09 21:10:475316 ** name in the following format:
5317 **
5318 ** "<temporary_directory>/etilqs_XXXXXXXXXXXXXXX\0\0"
5319 **
5320 ** If not, return SQLITE_ERROR. The number 17 is used here in order to
5321 ** account for the space used by the 15 character random suffix and the
5322 ** two trailing NUL characters. The final directory separator character
5323 ** has already added if it was not already present.
5324 */
5325 nLen = sqlite3Strlen30(zBuf);
5326 if( (nLen + nPre + 17) > nBuf ){
5327 sqlite3_free(zBuf);
5328 OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
5329 return winLogError(SQLITE_ERROR, 0, "winGetTempname5", 0);
5330 }
shanehe2ad9312010-07-08 03:13:335331
mistachkinfd4b90b2013-11-09 21:10:475332 sqlite3_snprintf(nBuf-16-nLen, zBuf+nLen, SQLITE_TEMP_FILE_PREFIX);
shanehe2ad9312010-07-08 03:13:335333
drhea678832008-12-10 19:26:225334 j = sqlite3Strlen30(zBuf);
shanehe2ad9312010-07-08 03:13:335335 sqlite3_randomness(15, &zBuf[j]);
drh7309b502023-08-16 15:10:075336 pid = osGetCurrentProcessId();
shanehe2ad9312010-07-08 03:13:335337 for(i=0; i<15; i++, j++){
drh7309b502023-08-16 15:10:075338 zBuf[j] += pid & 0xff;
5339 pid >>= 8;
danielk197717b90b52008-06-06 11:11:255340 zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
5341 }
5342 zBuf[j] = 0;
mistachkine2909192012-01-11 01:01:025343 zBuf[j+1] = 0;
mistachkin37418272013-08-28 05:49:395344 *pzBuf = zBuf;
shanehe2ad9312010-07-08 03:13:335345
mistachkinf2c1c992013-04-28 01:44:435346 OSTRACE(("TEMP-FILENAME name=%s, rc=SQLITE_OK\n", zBuf));
5347 return SQLITE_OK;
danielk197717b90b52008-06-06 11:11:255348}
5349
shane820800d2008-07-22 05:32:035350/*
drh1e039a22012-05-07 13:15:205351** Return TRUE if the named file is really a directory. Return false if
5352** it is something other than a directory, or if there is any kind of memory
5353** allocation failure.
5354*/
mistachkin48a55aa2012-05-07 17:16:075355static int winIsDir(const void *zConverted){
5356 DWORD attr;
5357 int rc = 0;
5358 DWORD lastErrno;
drh1e039a22012-05-07 13:15:205359
mistachkinb324bc72013-08-28 02:37:295360 if( osIsNT() ){
mistachkin48a55aa2012-05-07 17:16:075361 int cnt = 0;
5362 WIN32_FILE_ATTRIBUTE_DATA sAttrData;
5363 memset(&sAttrData, 0, sizeof(sAttrData));
5364 while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
5365 GetFileExInfoStandard,
mistachkinb324bc72013-08-28 02:37:295366 &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){}
mistachkin48a55aa2012-05-07 17:16:075367 if( !rc ){
5368 return 0; /* Invalid name? */
5369 }
5370 attr = sAttrData.dwFileAttributes;
stephan42e5ceb2025-03-10 15:15:135371#if SQLITE_OS_WINCE==0 && defined(SQLITE_WIN32_HAS_ANSI)
drh1e039a22012-05-07 13:15:205372 }else{
mistachkin48a55aa2012-05-07 17:16:075373 attr = osGetFileAttributesA((char*)zConverted);
5374#endif
drh1e039a22012-05-07 13:15:205375 }
mistachkin48a55aa2012-05-07 17:16:075376 return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY);
drh1e039a22012-05-07 13:15:205377}
5378
drh0e97e9a2017-09-21 20:43:485379/* forward reference */
5380static int winAccess(
5381 sqlite3_vfs *pVfs, /* Not used on win32 */
5382 const char *zFilename, /* Name of file to check */
5383 int flags, /* Type of test to make on this file */
5384 int *pResOut /* OUT: Result */
5385);
5386
shane820800d2008-07-22 05:32:035387/*
drh517a0e02025-03-26 14:45:155388** The Windows version of xAccess() accepts an extra bit in the flags
5389** parameter that prevents an anti-virus retry loop.
5390*/
5391#define NORETRY 0x4000
5392
5393/*
drh153c62c2007-08-24 03:51:335394** Open a file.
5395*/
5396static int winOpen(
mistachkin1e754832016-07-08 21:14:375397 sqlite3_vfs *pVfs, /* Used to get maximum path length and AppData */
drh153c62c2007-08-24 03:51:335398 const char *zName, /* Name of the file (UTF-8) */
5399 sqlite3_file *id, /* Write the SQLite file handle here */
5400 int flags, /* Open mode flags */
5401 int *pOutFlags /* Status return flags */
5402){
5403 HANDLE h;
mistachkin99391182013-11-11 02:46:325404 DWORD lastErrno = 0;
drh153c62c2007-08-24 03:51:335405 DWORD dwDesiredAccess;
5406 DWORD dwShareMode;
5407 DWORD dwCreationDisposition;
5408 DWORD dwFlagsAndAttributes = 0;
shaned94b0552008-09-30 04:20:075409#if SQLITE_OS_WINCE
5410 int isTemp = 0;
5411#endif
mistachkin1e754832016-07-08 21:14:375412 winVfsAppData *pAppData;
drh153c62c2007-08-24 03:51:335413 winFile *pFile = (winFile*)id;
shanehf7b5f852010-08-24 20:46:535414 void *zConverted; /* Filename in OS encoding */
5415 const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */
mistachkinfda06be2011-08-02 00:57:345416 int cnt = 0;
drh4a6de7f2025-03-26 15:51:055417 int isRO = 0; /* file is known to be accessible readonly */
shanehf7b5f852010-08-24 20:46:535418
5419 /* If argument zPath is a NULL pointer, this function is required to open
5420 ** a temporary file. Use this buffer to store the file name in.
5421 */
mistachkin37418272013-08-28 05:49:395422 char *zTmpname = 0; /* For temporary filename, if necessary. */
shanehf7b5f852010-08-24 20:46:535423
5424 int rc = SQLITE_OK; /* Function Return Code */
shanehbd2aaf92010-09-01 02:38:215425#if !defined(NDEBUG) || SQLITE_OS_WINCE
drh9bf5bea2024-11-21 01:50:015426 int eType = flags&0x0FFF00; /* Type of file to open */
shanehbd2aaf92010-09-01 02:38:215427#endif
shanehf7b5f852010-08-24 20:46:535428
5429 int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
5430 int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
5431 int isCreate = (flags & SQLITE_OPEN_CREATE);
5432 int isReadonly = (flags & SQLITE_OPEN_READONLY);
5433 int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
5434
shanehbd2aaf92010-09-01 02:38:215435#ifndef NDEBUG
shanehf7b5f852010-08-24 20:46:535436 int isOpenJournal = (isCreate && (
drhccb21132020-06-19 11:34:575437 eType==SQLITE_OPEN_SUPER_JOURNAL
mistachkin17835a52014-08-06 03:06:015438 || eType==SQLITE_OPEN_MAIN_JOURNAL
shanehf7b5f852010-08-24 20:46:535439 || eType==SQLITE_OPEN_WAL
5440 ));
shanehbd2aaf92010-09-01 02:38:215441#endif
shanehf7b5f852010-08-24 20:46:535442
mistachkinf2c1c992013-04-28 01:44:435443 OSTRACE(("OPEN name=%s, pFile=%p, flags=%x, pOutFlags=%p\n",
5444 zUtf8Name, id, flags, pOutFlags));
5445
mistachkin17835a52014-08-06 03:06:015446 /* Check the following statements are true:
shanehf7b5f852010-08-24 20:46:535447 **
mistachkin17835a52014-08-06 03:06:015448 ** (a) Exactly one of the READWRITE and READONLY flags must be set, and
shanehf7b5f852010-08-24 20:46:535449 ** (b) if CREATE is set, then READWRITE must also be set, and
5450 ** (c) if EXCLUSIVE is set, then CREATE must also be set.
5451 ** (d) if DELETEONCLOSE is set, then CREATE must also be set.
5452 */
5453 assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
5454 assert(isCreate==0 || isReadWrite);
5455 assert(isExclusive==0 || isCreate);
5456 assert(isDelete==0 || isCreate);
5457
drh067b92b2020-06-19 15:24:125458 /* The main DB, main journal, WAL file and super-journal are never
shanehf7b5f852010-08-24 20:46:535459 ** automatically deleted. Nor are they ever temporary files. */
5460 assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
5461 assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
drhccb21132020-06-19 11:34:575462 assert( (!isDelete && zName) || eType!=SQLITE_OPEN_SUPER_JOURNAL );
shanehf7b5f852010-08-24 20:46:535463 assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
5464
5465 /* Assert that the upper layer has set one of the "file-type" flags. */
mistachkin17835a52014-08-06 03:06:015466 assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
5467 || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
drhccb21132020-06-19 11:34:575468 || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_SUPER_JOURNAL
shanehf7b5f852010-08-24 20:46:535469 || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
5470 );
danielk197717b90b52008-06-06 11:11:255471
mistachkin9ce59a92013-02-13 22:54:035472 assert( pFile!=0 );
5473 memset(pFile, 0, sizeof(winFile));
shaneh04882a92010-05-11 02:49:395474 pFile->h = INVALID_HANDLE_VALUE;
5475
mistachkinaf529732012-08-28 04:20:565476#if SQLITE_OS_WINRT
mistachkin533fb6d2013-08-28 02:26:485477 if( !zUtf8Name && !sqlite3_temp_directory ){
mistachkinaf529732012-08-28 04:20:565478 sqlite3_log(SQLITE_ERROR,
5479 "sqlite3_temp_directory variable should be set for WinRT");
5480 }
5481#endif
5482
mistachkin17835a52014-08-06 03:06:015483 /* If the second argument to this function is NULL, generate a
5484 ** temporary file name to use
danielk197717b90b52008-06-06 11:11:255485 */
5486 if( !zUtf8Name ){
mistachkin533fb6d2013-08-28 02:26:485487 assert( isDelete && !isOpenJournal );
mistachkin37418272013-08-28 05:49:395488 rc = winGetTempname(pVfs, &zTmpname);
danielk197717b90b52008-06-06 11:11:255489 if( rc!=SQLITE_OK ){
mistachkine84d8d32013-04-29 03:09:105490 OSTRACE(("OPEN name=%s, rc=%s", zUtf8Name, sqlite3ErrName(rc)));
danielk197717b90b52008-06-06 11:11:255491 return rc;
5492 }
5493 zUtf8Name = zTmpname;
5494 }
5495
mistachkine2909192012-01-11 01:01:025496 /* Database filenames are double-zero terminated if they are not
5497 ** URIs with parameters. Hence, they can always be passed into
5498 ** sqlite3_uri_parameter().
5499 */
5500 assert( (eType!=SQLITE_OPEN_MAIN_DB) || (flags & SQLITE_OPEN_URI) ||
mistachkin533fb6d2013-08-28 02:26:485501 zUtf8Name[sqlite3Strlen30(zUtf8Name)+1]==0 );
mistachkine2909192012-01-11 01:01:025502
danielk197717b90b52008-06-06 11:11:255503 /* Convert the filename to the system encoding. */
mistachkind95a3d32013-08-30 21:52:385504 zConverted = winConvertFromUtf8Filename(zUtf8Name);
drh153c62c2007-08-24 03:51:335505 if( zConverted==0 ){
mistachkin37418272013-08-28 05:49:395506 sqlite3_free(zTmpname);
mistachkinf2c1c992013-04-28 01:44:435507 OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name));
mistachkinfad30392016-02-13 23:43:465508 return SQLITE_IOERR_NOMEM_BKPT;
drh153c62c2007-08-24 03:51:335509 }
5510
mistachkin48a55aa2012-05-07 17:16:075511 if( winIsDir(zConverted) ){
5512 sqlite3_free(zConverted);
mistachkin37418272013-08-28 05:49:395513 sqlite3_free(zTmpname);
mistachkinf2c1c992013-04-28 01:44:435514 OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8Name));
mistachkin48a55aa2012-05-07 17:16:075515 return SQLITE_CANTOPEN_ISDIR;
5516 }
5517
shanehf7b5f852010-08-24 20:46:535518 if( isReadWrite ){
drh153c62c2007-08-24 03:51:335519 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
5520 }else{
5521 dwDesiredAccess = GENERIC_READ;
5522 }
shanehf7b5f852010-08-24 20:46:535523
mistachkin17835a52014-08-06 03:06:015524 /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is
5525 ** created. SQLite doesn't use it to indicate "exclusive access"
shane68d405e2009-04-23 19:08:325526 ** as it is usually understood.
5527 */
shanehf7b5f852010-08-24 20:46:535528 if( isExclusive ){
shane68d405e2009-04-23 19:08:325529 /* Creates a new file, only if it does not already exist. */
5530 /* If the file exists, it fails. */
5531 dwCreationDisposition = CREATE_NEW;
shanehf7b5f852010-08-24 20:46:535532 }else if( isCreate ){
shane68d405e2009-04-23 19:08:325533 /* Open existing file, or create if it doesn't exist */
drh153c62c2007-08-24 03:51:335534 dwCreationDisposition = OPEN_ALWAYS;
5535 }else{
shane68d405e2009-04-23 19:08:325536 /* Opens a file, only if it exists. */
drh153c62c2007-08-24 03:51:335537 dwCreationDisposition = OPEN_EXISTING;
5538 }
shanehf7b5f852010-08-24 20:46:535539
drhf8c4c3a2020-10-15 14:37:275540 if( 0==sqlite3_uri_boolean(zName, "exclusive", 0) ){
5541 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
5542 }else{
5543 dwShareMode = 0;
5544 }
shanehf7b5f852010-08-24 20:46:535545
5546 if( isDelete ){
danielk197729bafea2008-06-26 10:41:195547#if SQLITE_OS_WINCE
drh0cd1ea52007-10-08 15:06:035548 dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN;
shaned94b0552008-09-30 04:20:075549 isTemp = 1;
drh0cd1ea52007-10-08 15:06:035550#else
drh153c62c2007-08-24 03:51:335551 dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY
5552 | FILE_ATTRIBUTE_HIDDEN
5553 | FILE_FLAG_DELETE_ON_CLOSE;
drh0cd1ea52007-10-08 15:06:035554#endif
drh153c62c2007-08-24 03:51:335555 }else{
5556 dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
5557 }
drh496936c2007-10-08 12:21:105558 /* Reports from the internet are that performance is always
5559 ** better if FILE_FLAG_RANDOM_ACCESS is used. Ticket #2699. */
shaned94b0552008-09-30 04:20:075560#if SQLITE_OS_WINCE
drh496936c2007-10-08 12:21:105561 dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
shaned94b0552008-09-30 04:20:075562#endif
shanehf7b5f852010-08-24 20:46:535563
mistachkinb324bc72013-08-28 02:37:295564 if( osIsNT() ){
mistachkindf562d52012-03-13 01:16:575565#if SQLITE_OS_WINRT
mistachkin5483f772012-03-07 20:11:475566 CREATEFILE2_EXTENDED_PARAMETERS extendedParameters;
5567 extendedParameters.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
5568 extendedParameters.dwFileAttributes =
5569 dwFlagsAndAttributes & FILE_ATTRIBUTE_MASK;
5570 extendedParameters.dwFileFlags = dwFlagsAndAttributes & FILE_FLAG_MASK;
5571 extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS;
5572 extendedParameters.lpSecurityAttributes = NULL;
5573 extendedParameters.hTemplateFile = NULL;
mistachkin33140622017-09-22 16:23:235574 do{
5575 h = osCreateFile2((LPCWSTR)zConverted,
5576 dwDesiredAccess,
5577 dwShareMode,
5578 dwCreationDisposition,
5579 &extendedParameters);
5580 if( h!=INVALID_HANDLE_VALUE ) break;
5581 if( isReadWrite ){
drh4a6de7f2025-03-26 15:51:055582 int rc2;
mistachkin56852572018-01-17 01:26:055583 sqlite3BeginBenignMalloc();
drh517a0e02025-03-26 14:45:155584 rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ|NORETRY, &isRO);
mistachkin56852572018-01-17 01:26:055585 sqlite3EndBenignMalloc();
mistachkin33140622017-09-22 16:23:235586 if( rc2==SQLITE_OK && isRO ) break;
5587 }
5588 }while( winRetryIoerr(&cnt, &lastErrno) );
mistachkin5483f772012-03-07 20:11:475589#else
drh0e97e9a2017-09-21 20:43:485590 do{
5591 h = osCreateFileW((LPCWSTR)zConverted,
5592 dwDesiredAccess,
5593 dwShareMode, NULL,
5594 dwCreationDisposition,
5595 dwFlagsAndAttributes,
5596 NULL);
5597 if( h!=INVALID_HANDLE_VALUE ) break;
5598 if( isReadWrite ){
drh4a6de7f2025-03-26 15:51:055599 int rc2;
mistachkin56852572018-01-17 01:26:055600 sqlite3BeginBenignMalloc();
drh517a0e02025-03-26 14:45:155601 rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ|NORETRY, &isRO);
mistachkin56852572018-01-17 01:26:055602 sqlite3EndBenignMalloc();
drh0e97e9a2017-09-21 20:43:485603 if( rc2==SQLITE_OK && isRO ) break;
5604 }
5605 }while( winRetryIoerr(&cnt, &lastErrno) );
mistachkin5483f772012-03-07 20:11:475606#endif
drhd52ee722012-03-02 00:00:475607 }
5608#ifdef SQLITE_WIN32_HAS_ANSI
5609 else{
mistachkin33140622017-09-22 16:23:235610 do{
5611 h = osCreateFileA((LPCSTR)zConverted,
5612 dwDesiredAccess,
5613 dwShareMode, NULL,
5614 dwCreationDisposition,
5615 dwFlagsAndAttributes,
5616 NULL);
5617 if( h!=INVALID_HANDLE_VALUE ) break;
5618 if( isReadWrite ){
drh4a6de7f2025-03-26 15:51:055619 int rc2;
mistachkin56852572018-01-17 01:26:055620 sqlite3BeginBenignMalloc();
drh517a0e02025-03-26 14:45:155621 rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ|NORETRY, &isRO);
mistachkin56852572018-01-17 01:26:055622 sqlite3EndBenignMalloc();
mistachkin33140622017-09-22 16:23:235623 if( rc2==SQLITE_OK && isRO ) break;
5624 }
5625 }while( winRetryIoerr(&cnt, &lastErrno) );
drh153c62c2007-08-24 03:51:335626 }
drhd52ee722012-03-02 00:00:475627#endif
drh21aa6a12015-03-26 15:27:325628 winLogIoerr(cnt, __LINE__);
mistachkinfda06be2011-08-02 00:57:345629
mistachkinf2c1c992013-04-28 01:44:435630 OSTRACE(("OPEN file=%p, name=%s, access=%lx, rc=%s\n", h, zUtf8Name,
5631 dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
shanehf7b5f852010-08-24 20:46:535632
drh153c62c2007-08-24 03:51:335633 if( h==INVALID_HANDLE_VALUE ){
mistachkin5f075382011-11-11 23:31:045634 sqlite3_free(zConverted);
mistachkin37418272013-08-28 05:49:395635 sqlite3_free(zTmpname);
drh4a6de7f2025-03-26 15:51:055636 if( isReadWrite && isRO && !isExclusive ){
mistachkin17835a52014-08-06 03:06:015637 return winOpen(pVfs, zName, id,
drh14880522013-03-01 23:24:045638 ((flags|SQLITE_OPEN_READONLY) &
5639 ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
5640 pOutFlags);
drh153c62c2007-08-24 03:51:335641 }else{
drhb40d9ee2017-09-21 20:03:175642 pFile->lastErrno = lastErrno;
5643 winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
drh9978c972010-02-23 17:36:325644 return SQLITE_CANTOPEN_BKPT;
drh153c62c2007-08-24 03:51:335645 }
5646 }
shanehf7b5f852010-08-24 20:46:535647
drh153c62c2007-08-24 03:51:335648 if( pOutFlags ){
shanehf7b5f852010-08-24 20:46:535649 if( isReadWrite ){
drh153c62c2007-08-24 03:51:335650 *pOutFlags = SQLITE_OPEN_READWRITE;
5651 }else{
5652 *pOutFlags = SQLITE_OPEN_READONLY;
5653 }
5654 }
shanehf7b5f852010-08-24 20:46:535655
mistachkine84d8d32013-04-29 03:09:105656 OSTRACE(("OPEN file=%p, name=%s, access=%lx, pOutFlags=%p, *pOutFlags=%d, "
5657 "rc=%s\n", h, zUtf8Name, dwDesiredAccess, pOutFlags, pOutFlags ?
5658 *pOutFlags : 0, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
shanehf7b5f852010-08-24 20:46:535659
mistachkin1e754832016-07-08 21:14:375660 pAppData = (winVfsAppData*)pVfs->pAppData;
5661
danielk197729bafea2008-06-26 10:41:195662#if SQLITE_OS_WINCE
mistachkin1e754832016-07-08 21:14:375663 {
5664 if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
5665 && ((pAppData==NULL) || !pAppData->bNoLock)
5666 && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
5667 ){
5668 osCloseHandle(h);
5669 sqlite3_free(zConverted);
5670 sqlite3_free(zTmpname);
5671 OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc)));
5672 return rc;
5673 }
drh153c62c2007-08-24 03:51:335674 }
drhfc3afb62007-10-09 15:36:105675 if( isTemp ){
drh153c62c2007-08-24 03:51:335676 pFile->zDeleteOnClose = zConverted;
5677 }else
5678#endif
5679 {
mistachkin5f075382011-11-11 23:31:045680 sqlite3_free(zConverted);
drh153c62c2007-08-24 03:51:335681 }
shanehf7b5f852010-08-24 20:46:535682
mistachkinc2165662013-10-16 09:49:105683 sqlite3_free(zTmpname);
drh0c52f5a2020-07-24 09:17:425684 id->pMethods = pAppData ? pAppData->pMethod : &winIoMethod;
mistachkin9ce59a92013-02-13 22:54:035685 pFile->pVfs = pVfs;
5686 pFile->h = h;
mistachkindaf9a5a2013-03-23 09:56:395687 if( isReadonly ){
5688 pFile->ctrlFlags |= WINFILE_RDONLY;
5689 }
dan10757ed2020-05-19 15:40:075690 if( (flags & SQLITE_OPEN_MAIN_DB)
5691 && sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE)
5692 ){
mistachkin9ce59a92013-02-13 22:54:035693 pFile->ctrlFlags |= WINFILE_PSOW;
5694 }
5695 pFile->lastErrno = NO_ERROR;
5696 pFile->zPath = zName;
mistachkin5824e052013-04-15 20:08:275697#if SQLITE_MAX_MMAP_SIZE>0
mistachkindaf9a5a2013-03-23 09:56:395698 pFile->hMap = NULL;
5699 pFile->pMapRegion = 0;
5700 pFile->mmapSize = 0;
danede01a92013-05-17 12:10:525701 pFile->mmapSizeMax = sqlite3GlobalConfig.szMmap;
mistachkin5824e052013-04-15 20:08:275702#endif
mistachkin9ce59a92013-02-13 22:54:035703
drhaf5f0402007-09-03 17:09:035704 OpenCounter(+1);
shanehf7b5f852010-08-24 20:46:535705 return rc;
drh153c62c2007-08-24 03:51:335706}
5707
5708/*
5709** Delete the named file.
5710**
mistachkin318507b2011-11-11 22:08:545711** Note that Windows does not allow a file to be deleted if some other
drh153c62c2007-08-24 03:51:335712** process has it open. Sometimes a virus scanner or indexing program
5713** will open a journal file shortly after it is created in order to do
shane3582c5a2008-07-31 01:34:345714** whatever it does. While this other process is holding the
drh153c62c2007-08-24 03:51:335715** file open, we will be unable to delete it. To work around this
5716** problem, we delay 100 milliseconds and try to delete again. Up
5717** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
5718** up and returning an error.
5719*/
drh153c62c2007-08-24 03:51:335720static int winDelete(
5721 sqlite3_vfs *pVfs, /* Not used on win32 */
5722 const char *zFilename, /* Name of file to delete */
5723 int syncDir /* Not used on win32 */
5724){
5725 int cnt = 0;
drh52564d72011-07-12 11:04:185726 int rc;
mistachkin48a55aa2012-05-07 17:16:075727 DWORD attr;
mistachkin99391182013-11-11 02:46:325728 DWORD lastErrno = 0;
shanehe2ad9312010-07-08 03:13:335729 void *zConverted;
shane18e526c2008-12-10 22:30:245730 UNUSED_PARAMETER(pVfs);
5731 UNUSED_PARAMETER(syncDir);
shanehe2ad9312010-07-08 03:13:335732
5733 SimulateIOError(return SQLITE_IOERR_DELETE);
mistachkinf2c1c992013-04-28 01:44:435734 OSTRACE(("DELETE name=%s, syncDir=%d\n", zFilename, syncDir));
5735
mistachkind95a3d32013-08-30 21:52:385736 zConverted = winConvertFromUtf8Filename(zFilename);
drh153c62c2007-08-24 03:51:335737 if( zConverted==0 ){
mistachkin533fb6d2013-08-28 02:26:485738 OSTRACE(("DELETE name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
mistachkinfad30392016-02-13 23:43:465739 return SQLITE_IOERR_NOMEM_BKPT;
drh153c62c2007-08-24 03:51:335740 }
mistachkinb324bc72013-08-28 02:37:295741 if( osIsNT() ){
mistachkin48a55aa2012-05-07 17:16:075742 do {
mistachkin287a48d2012-03-03 13:15:255743#if SQLITE_OS_WINRT
mistachkinfcd2f122012-05-07 20:28:195744 WIN32_FILE_ATTRIBUTE_DATA sAttrData;
5745 memset(&sAttrData, 0, sizeof(sAttrData));
5746 if ( osGetFileAttributesExW(zConverted, GetFileExInfoStandard,
5747 &sAttrData) ){
5748 attr = sAttrData.dwFileAttributes;
5749 }else{
mistachkin55fbc862012-11-21 02:10:205750 lastErrno = osGetLastError();
drh14880522013-03-01 23:24:045751 if( lastErrno==ERROR_FILE_NOT_FOUND
5752 || lastErrno==ERROR_PATH_NOT_FOUND ){
mistachkin55fbc862012-11-21 02:10:205753 rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
5754 }else{
5755 rc = SQLITE_ERROR;
5756 }
mistachkinfcd2f122012-05-07 20:28:195757 break;
5758 }
mistachkin287a48d2012-03-03 13:15:255759#else
mistachkin48a55aa2012-05-07 17:16:075760 attr = osGetFileAttributesW(zConverted);
mistachkin287a48d2012-03-03 13:15:255761#endif
mistachkin48a55aa2012-05-07 17:16:075762 if ( attr==INVALID_FILE_ATTRIBUTES ){
mistachkin55fbc862012-11-21 02:10:205763 lastErrno = osGetLastError();
drh14880522013-03-01 23:24:045764 if( lastErrno==ERROR_FILE_NOT_FOUND
5765 || lastErrno==ERROR_PATH_NOT_FOUND ){
mistachkin55fbc862012-11-21 02:10:205766 rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
5767 }else{
5768 rc = SQLITE_ERROR;
5769 }
mistachkin48a55aa2012-05-07 17:16:075770 break;
5771 }
5772 if ( attr&FILE_ATTRIBUTE_DIRECTORY ){
5773 rc = SQLITE_ERROR; /* Files only. */
5774 break;
5775 }
5776 if ( osDeleteFileW(zConverted) ){
5777 rc = SQLITE_OK; /* Deleted OK. */
5778 break;
5779 }
mistachkinb324bc72013-08-28 02:37:295780 if ( !winRetryIoerr(&cnt, &lastErrno) ){
mistachkin48a55aa2012-05-07 17:16:075781 rc = SQLITE_ERROR; /* No more retries. */
5782 break;
5783 }
5784 } while(1);
drhd52ee722012-03-02 00:00:475785 }
5786#ifdef SQLITE_WIN32_HAS_ANSI
5787 else{
mistachkin48a55aa2012-05-07 17:16:075788 do {
5789 attr = osGetFileAttributesA(zConverted);
5790 if ( attr==INVALID_FILE_ATTRIBUTES ){
mistachkin55fbc862012-11-21 02:10:205791 lastErrno = osGetLastError();
drh14880522013-03-01 23:24:045792 if( lastErrno==ERROR_FILE_NOT_FOUND
5793 || lastErrno==ERROR_PATH_NOT_FOUND ){
mistachkin55fbc862012-11-21 02:10:205794 rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
5795 }else{
5796 rc = SQLITE_ERROR;
5797 }
mistachkin48a55aa2012-05-07 17:16:075798 break;
5799 }
5800 if ( attr&FILE_ATTRIBUTE_DIRECTORY ){
5801 rc = SQLITE_ERROR; /* Files only. */
5802 break;
5803 }
5804 if ( osDeleteFileA(zConverted) ){
5805 rc = SQLITE_OK; /* Deleted OK. */
5806 break;
5807 }
mistachkinb324bc72013-08-28 02:37:295808 if ( !winRetryIoerr(&cnt, &lastErrno) ){
mistachkin48a55aa2012-05-07 17:16:075809 rc = SQLITE_ERROR; /* No more retries. */
5810 break;
5811 }
5812 } while(1);
drh153c62c2007-08-24 03:51:335813 }
drhd52ee722012-03-02 00:00:475814#endif
drh6d405c22012-11-20 15:06:575815 if( rc && rc!=SQLITE_IOERR_DELETE_NOENT ){
mistachkin9f11ef12013-08-31 02:48:565816 rc = winLogError(SQLITE_IOERR_DELETE, lastErrno, "winDelete", zFilename);
drha32ad842011-07-12 13:51:055817 }else{
drh21aa6a12015-03-26 15:27:325818 winLogIoerr(cnt, __LINE__);
drha32ad842011-07-12 13:51:055819 }
mistachkin5f075382011-11-11 23:31:045820 sqlite3_free(zConverted);
mistachkinf2c1c992013-04-28 01:44:435821 OSTRACE(("DELETE name=%s, rc=%s\n", zFilename, sqlite3ErrName(rc)));
drh52564d72011-07-12 11:04:185822 return rc;
drh153c62c2007-08-24 03:51:335823}
5824
5825/*
mistachkin48864df2013-03-21 21:20:325826** Check the existence and status of a file.
drh153c62c2007-08-24 03:51:335827*/
5828static int winAccess(
5829 sqlite3_vfs *pVfs, /* Not used on win32 */
5830 const char *zFilename, /* Name of file to check */
danielk1977861f7452008-06-05 11:39:115831 int flags, /* Type of test to make on this file */
5832 int *pResOut /* OUT: Result */
drh153c62c2007-08-24 03:51:335833){
5834 DWORD attr;
drhea678832008-12-10 19:26:225835 int rc = 0;
mistachkin99391182013-11-11 02:46:325836 DWORD lastErrno = 0;
shanehcce1b682010-07-07 14:45:405837 void *zConverted;
drh517a0e02025-03-26 14:45:155838 int noRetry = 0; /* Do not use winRetryIoerr() */
shane18e526c2008-12-10 22:30:245839 UNUSED_PARAMETER(pVfs);
shanehcce1b682010-07-07 14:45:405840
drh517a0e02025-03-26 14:45:155841 if( (flags & NORETRY)!=0 ){
5842 noRetry = 1;
5843 flags &= ~NORETRY;
5844 }
5845
shanehcce1b682010-07-07 14:45:405846 SimulateIOError( return SQLITE_IOERR_ACCESS; );
mistachkinf2c1c992013-04-28 01:44:435847 OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n",
5848 zFilename, flags, pResOut));
5849
mistachkincf5dce02023-04-27 21:31:215850 if( zFilename==0 ){
5851 *pResOut = 0;
5852 OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
5853 zFilename, pResOut, *pResOut));
5854 return SQLITE_OK;
5855 }
5856
mistachkind95a3d32013-08-30 21:52:385857 zConverted = winConvertFromUtf8Filename(zFilename);
drh153c62c2007-08-24 03:51:335858 if( zConverted==0 ){
mistachkinf2c1c992013-04-28 01:44:435859 OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
mistachkinfad30392016-02-13 23:43:465860 return SQLITE_IOERR_NOMEM_BKPT;
drh153c62c2007-08-24 03:51:335861 }
mistachkinb324bc72013-08-28 02:37:295862 if( osIsNT() ){
drhfdf6db12011-07-22 21:25:575863 int cnt = 0;
drh722a7e92010-07-05 21:00:435864 WIN32_FILE_ATTRIBUTE_DATA sAttrData;
5865 memset(&sAttrData, 0, sizeof(sAttrData));
mistachkin318507b2011-11-11 22:08:545866 while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
mistachkin17835a52014-08-06 03:06:015867 GetFileExInfoStandard,
drh517a0e02025-03-26 14:45:155868 &sAttrData))
5869 && !noRetry
5870 && winRetryIoerr(&cnt, &lastErrno)
5871 ){ /* Loop until true */}
drhfdf6db12011-07-22 21:25:575872 if( rc ){
shaneh7ea72592010-07-07 13:58:115873 /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file
5874 ** as if it does not exist.
5875 */
5876 if( flags==SQLITE_ACCESS_EXISTS
mistachkin17835a52014-08-06 03:06:015877 && sAttrData.nFileSizeHigh==0
shaneh7ea72592010-07-07 13:58:115878 && sAttrData.nFileSizeLow==0 ){
5879 attr = INVALID_FILE_ATTRIBUTES;
5880 }else{
5881 attr = sAttrData.dwFileAttributes;
5882 }
5883 }else{
drh21aa6a12015-03-26 15:27:325884 winLogIoerr(cnt, __LINE__);
drh19038f1b72012-08-31 12:31:185885 if( lastErrno!=ERROR_FILE_NOT_FOUND && lastErrno!=ERROR_PATH_NOT_FOUND ){
mistachkin5f075382011-11-11 23:31:045886 sqlite3_free(zConverted);
mistachkin9f11ef12013-08-31 02:48:565887 return winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess",
5888 zFilename);
shanehcce1b682010-07-07 14:45:405889 }else{
5890 attr = INVALID_FILE_ATTRIBUTES;
5891 }
drh722a7e92010-07-05 21:00:435892 }
drh153c62c2007-08-24 03:51:335893 }
drhd52ee722012-03-02 00:00:475894#ifdef SQLITE_WIN32_HAS_ANSI
5895 else{
5896 attr = osGetFileAttributesA((char*)zConverted);
5897 }
5898#endif
mistachkin5f075382011-11-11 23:31:045899 sqlite3_free(zConverted);
drh153c62c2007-08-24 03:51:335900 switch( flags ){
drh50d3f902007-08-27 21:10:365901 case SQLITE_ACCESS_READ:
drh153c62c2007-08-24 03:51:335902 case SQLITE_ACCESS_EXISTS:
shane820800d2008-07-22 05:32:035903 rc = attr!=INVALID_FILE_ATTRIBUTES;
drh153c62c2007-08-24 03:51:335904 break;
5905 case SQLITE_ACCESS_READWRITE:
mistachkin4e6b49b2011-07-28 19:16:415906 rc = attr!=INVALID_FILE_ATTRIBUTES &&
5907 (attr & FILE_ATTRIBUTE_READONLY)==0;
drh153c62c2007-08-24 03:51:335908 break;
drh153c62c2007-08-24 03:51:335909 default:
5910 assert(!"Invalid flags argument");
5911 }
danielk1977861f7452008-06-05 11:39:115912 *pResOut = rc;
mistachkinf2c1c992013-04-28 01:44:435913 OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
5914 zFilename, pResOut, *pResOut));
danielk1977861f7452008-06-05 11:39:115915 return SQLITE_OK;
drh054889e2005-11-30 03:20:315916}
5917
mistachkind95a3d32013-08-30 21:52:385918/*
mistachkina8e41ec2020-05-15 01:18:075919** Returns non-zero if the specified path name starts with the "long path"
5920** prefix.
5921*/
5922static BOOL winIsLongPathPrefix(
5923 const char *zPathname
5924){
5925 return ( zPathname[0]=='\\' && zPathname[1]=='\\'
5926 && zPathname[2]=='?' && zPathname[3]=='\\' );
5927}
5928
5929/*
mistachkind95a3d32013-08-30 21:52:385930** Returns non-zero if the specified path name starts with a drive letter
5931** followed by a colon character.
5932*/
5933static BOOL winIsDriveLetterAndColon(
5934 const char *zPathname
5935){
5936 return ( sqlite3Isalpha(zPathname[0]) && zPathname[1]==':' );
5937}
drh054889e2005-11-30 03:20:315938
stephan42e5ceb2025-03-10 15:15:135939#ifdef _WIN32
drh153c62c2007-08-24 03:51:335940/*
mistachkina112d142012-03-14 00:44:015941** Returns non-zero if the specified path name should be used verbatim. If
5942** non-zero is returned from this function, the calling function must simply
5943** use the provided path name verbatim -OR- resolve it into a full path name
5944** using the GetFullPathName Win32 API function (if available).
5945*/
5946static BOOL winIsVerbatimPathname(
5947 const char *zPathname
5948){
5949 /*
5950 ** If the path name starts with a forward slash or a backslash, it is either
5951 ** a legal UNC name, a volume relative path, or an absolute path name in the
5952 ** "Unix" format on Windows. There is no easy way to differentiate between
5953 ** the final two cases; therefore, we return the safer return value of TRUE
5954 ** so that callers of this function will simply use it verbatim.
5955 */
mistachkin533fb6d2013-08-28 02:26:485956 if ( winIsDirSep(zPathname[0]) ){
mistachkina112d142012-03-14 00:44:015957 return TRUE;
5958 }
5959
5960 /*
5961 ** If the path name starts with a letter and a colon it is either a volume
5962 ** relative path or an absolute path. Callers of this function must not
5963 ** attempt to treat it as a relative path name (i.e. they should simply use
5964 ** it verbatim).
5965 */
mistachkind95a3d32013-08-30 21:52:385966 if ( winIsDriveLetterAndColon(zPathname) ){
mistachkina112d142012-03-14 00:44:015967 return TRUE;
5968 }
5969
5970 /*
5971 ** If we get to this point, the path name should almost certainly be a purely
5972 ** relative one (i.e. not a UNC name, not absolute, and not volume relative).
5973 */
5974 return FALSE;
5975}
stephan42e5ceb2025-03-10 15:15:135976#endif /* _WIN32 */
5977
5978#ifdef __CYGWIN__
5979/*
5980** Simplify a filename into its canonical form
5981** by making the following changes:
5982**
5983** * convert any '/' to '\' (win32) or reverse (Cygwin)
5984** * removing any trailing and duplicate / (except for UNC paths)
5985** * convert /./ into just /
5986**
5987** Changes are made in-place. Return the new name length.
5988**
5989** The original filename is in z[0..]. If the path is shortened,
5990** no-longer used bytes will be written by '\0'.
5991*/
5992static void winSimplifyName(char *z){
5993 int i, j;
5994 for(i=j=0; z[i]; ++i){
5995 if( winIsDirSep(z[i]) ){
5996#if !defined(SQLITE_TEST)
5997 /* Some test-cases assume that "./foo" and "foo" are different */
5998 if( z[i+1]=='.' && winIsDirSep(z[i+2]) ){
5999 ++i;
6000 continue;
6001 }
6002#endif
6003 if( !z[i+1] || (winIsDirSep(z[i+1]) && (i!=0)) ){
6004 continue;
6005 }
6006 z[j++] = osGetenv?'/':'\\';
6007 }else{
6008 z[j++] = z[i];
6009 }
6010 }
6011 while(j<i) z[j++] = '\0';
6012}
6013
6014#define SQLITE_MAX_SYMLINKS 100
6015
6016static int mkFullPathname(
6017 const char *zPath, /* Input path */
6018 char *zOut, /* Output buffer */
6019 int nOut /* Allocated size of buffer zOut */
6020){
6021 int nPath = sqlite3Strlen30(zPath);
6022 int iOff = 0;
6023 if( zPath[0]!='/' ){
6024 if( osGetcwd(zOut, nOut-2)==0 ){
6025 return winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)osErrno, "getcwd", zPath);
6026 }
6027 iOff = sqlite3Strlen30(zOut);
6028 zOut[iOff++] = '/';
6029 }
6030 if( (iOff+nPath+1)>nOut ){
6031 /* SQLite assumes that xFullPathname() nul-terminates the output buffer
6032 ** even if it returns an error. */
6033 zOut[iOff] = '\0';
6034 return SQLITE_CANTOPEN_BKPT;
6035 }
6036 sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath);
6037 return SQLITE_OK;
6038}
6039#endif /* __CYGWIN__ */
mistachkina112d142012-03-14 00:44:016040
6041/*
drh153c62c2007-08-24 03:51:336042** Turn a relative pathname into a full pathname. Write the full
6043** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname
6044** bytes in size.
6045*/
drhfee64312022-09-02 11:12:166046static int winFullPathnameNoMutex(
danielk1977adfb9b02007-09-17 07:02:566047 sqlite3_vfs *pVfs, /* Pointer to vfs object */
6048 const char *zRelative, /* Possibly relative input path */
6049 int nFull, /* Size of output buffer in bytes */
6050 char *zFull /* Output buffer */
drh153c62c2007-08-24 03:51:336051){
stephan42e5ceb2025-03-10 15:15:136052#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
6053 int nByte;
mistachkin4a58d5f2016-06-06 20:36:266054 void *zConverted;
6055 char *zOut;
6056#endif
mistachkin17835a52014-08-06 03:06:016057
mistachkina8e41ec2020-05-15 01:18:076058 /* If this path name begins with "/X:" or "\\?\", where "X" is any
6059 ** alphabetic character, discard the initial "/" from the pathname.
drh8a5fd262016-06-06 20:27:156060 */
mistachkina8e41ec2020-05-15 01:18:076061 if( zRelative[0]=='/' && (winIsDriveLetterAndColon(zRelative+1)
6062 || winIsLongPathPrefix(zRelative+1)) ){
drh8a5fd262016-06-06 20:27:156063 zRelative++;
6064 }
6065
stephan42e5ceb2025-03-10 15:15:136066 SimulateIOError( return SQLITE_ERROR );
6067
6068#ifdef __CYGWIN__
6069 if( osGetcwd ){
6070 zFull[nFull-1] = '\0';
6071 if( !winIsDriveLetterAndColon(zRelative) || !winIsDirSep(zRelative[2]) ){
6072 int rc = SQLITE_OK;
6073 int nLink = 1; /* Number of symbolic links followed so far */
6074 const char *zIn = zRelative; /* Input path for each iteration of loop */
6075 char *zDel = 0;
6076 struct stat buf;
6077
6078 UNUSED_PARAMETER(pVfs);
6079
6080 do {
6081 /* Call lstat() on path zIn. Set bLink to true if the path is a symbolic
6082 ** link, or false otherwise. */
6083 int bLink = 0;
6084 if( osLstat && osReadlink ) {
6085 if( osLstat(zIn, &buf)!=0 ){
6086 int myErrno = osErrno;
6087 if( myErrno!=ENOENT ){
6088 rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)myErrno, "lstat", zIn);
6089 }
6090 }else{
6091 bLink = ((buf.st_mode & 0170000) == 0120000);
6092 }
6093
6094 if( bLink ){
6095 if( zDel==0 ){
6096 zDel = sqlite3MallocZero(nFull);
6097 if( zDel==0 ) rc = SQLITE_NOMEM;
6098 }else if( ++nLink>SQLITE_MAX_SYMLINKS ){
6099 rc = SQLITE_CANTOPEN_BKPT;
6100 }
6101
6102 if( rc==SQLITE_OK ){
6103 nByte = osReadlink(zIn, zDel, nFull-1);
6104 if( nByte ==(DWORD)-1 ){
6105 rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)osErrno, "readlink", zIn);
6106 }else{
6107 if( zDel[0]!='/' ){
6108 int n;
6109 for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--);
6110 if( nByte+n+1>nFull ){
6111 rc = SQLITE_CANTOPEN_BKPT;
6112 }else{
6113 memmove(&zDel[n], zDel, nByte+1);
6114 memcpy(zDel, zIn, n);
6115 nByte += n;
6116 }
6117 }
6118 zDel[nByte] = '\0';
6119 }
6120 }
6121
6122 zIn = zDel;
6123 }
6124 }
6125
6126 assert( rc!=SQLITE_OK || zIn!=zFull || zIn[0]=='/' );
6127 if( rc==SQLITE_OK && zIn!=zFull ){
6128 rc = mkFullPathname(zIn, zFull, nFull);
6129 }
6130 if( bLink==0 ) break;
6131 zIn = zFull;
6132 }while( rc==SQLITE_OK );
6133
6134 sqlite3_free(zDel);
6135 winSimplifyName(zFull);
6136 return rc;
6137 }
6138 }
6139#endif /* __CYGWIN__ */
drh153c62c2007-08-24 03:51:336140
stephan7b9407a2025-03-07 06:54:046141#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && defined(_WIN32)
shanehe2ad9312010-07-08 03:13:336142 SimulateIOError( return SQLITE_ERROR );
drh153c62c2007-08-24 03:51:336143 /* WinCE has no concept of a relative pathname, or so I am told. */
mistachkindf562d52012-03-13 01:16:576144 /* WinRT has no way to convert a relative path to an absolute one. */
mistachkina112d142012-03-14 00:44:016145 if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){
6146 /*
6147 ** NOTE: We are dealing with a relative path name and the data
6148 ** directory has been set. Therefore, use it as the basis
6149 ** for converting the relative path name to an absolute
6150 ** one by prepending the data directory and a backslash.
6151 */
mistachkin14eca4e2013-11-07 22:11:556152 sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
6153 sqlite3_data_directory, winGetDirSep(), zRelative);
mistachkina112d142012-03-14 00:44:016154 }else{
6155 sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative);
6156 }
drhe8256092007-10-09 15:20:396157 return SQLITE_OK;
drh153c62c2007-08-24 03:51:336158#endif
6159
stephan42e5ceb2025-03-10 15:15:136160#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
6161#if defined(_WIN32)
shanehe2ad9312010-07-08 03:13:336162 /* It's odd to simulate an io-error here, but really this is just
6163 ** using the io-error infrastructure to test that SQLite handles this
6164 ** function failing. This function could fail if, for example, the
6165 ** current working directory has been unlinked.
6166 */
6167 SimulateIOError( return SQLITE_ERROR );
mistachkina112d142012-03-14 00:44:016168 if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){
6169 /*
6170 ** NOTE: We are dealing with a relative path name and the data
6171 ** directory has been set. Therefore, use it as the basis
6172 ** for converting the relative path name to an absolute
6173 ** one by prepending the data directory and a backslash.
6174 */
mistachkin14eca4e2013-11-07 22:11:556175 sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
6176 sqlite3_data_directory, winGetDirSep(), zRelative);
mistachkina112d142012-03-14 00:44:016177 return SQLITE_OK;
6178 }
stephan42e5ceb2025-03-10 15:15:136179#endif
mistachkind95a3d32013-08-30 21:52:386180 zConverted = winConvertFromUtf8Filename(zRelative);
mistachkin5f075382011-11-11 23:31:046181 if( zConverted==0 ){
mistachkinfad30392016-02-13 23:43:466182 return SQLITE_IOERR_NOMEM_BKPT;
mistachkin5f075382011-11-11 23:31:046183 }
mistachkinb324bc72013-08-28 02:37:296184 if( osIsNT() ){
mistachkin318507b2011-11-11 22:08:546185 LPWSTR zTemp;
mistachkin7ea11af2012-09-13 15:24:296186 nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0);
6187 if( nByte==0 ){
mistachkin7ea11af2012-09-13 15:24:296188 sqlite3_free(zConverted);
mistachkin9f11ef12013-08-31 02:48:566189 return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(),
6190 "winFullPathname1", zRelative);
mistachkin7ea11af2012-09-13 15:24:296191 }
stephan42e5ceb2025-03-10 15:15:136192 nByte += 3;
6193 zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
drh153c62c2007-08-24 03:51:336194 if( zTemp==0 ){
mistachkin5f075382011-11-11 23:31:046195 sqlite3_free(zConverted);
mistachkinfad30392016-02-13 23:43:466196 return SQLITE_IOERR_NOMEM_BKPT;
drh153c62c2007-08-24 03:51:336197 }
stephan42e5ceb2025-03-10 15:15:136198 nByte = osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0);
mistachkin7ea11af2012-09-13 15:24:296199 if( nByte==0 ){
mistachkin7ea11af2012-09-13 15:24:296200 sqlite3_free(zConverted);
6201 sqlite3_free(zTemp);
mistachkin9f11ef12013-08-31 02:48:566202 return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(),
6203 "winFullPathname2", zRelative);
mistachkin7ea11af2012-09-13 15:24:296204 }
mistachkin5f075382011-11-11 23:31:046205 sqlite3_free(zConverted);
mistachkinb324bc72013-08-28 02:37:296206 zOut = winUnicodeToUtf8(zTemp);
mistachkin5f075382011-11-11 23:31:046207 sqlite3_free(zTemp);
drhd52ee722012-03-02 00:00:476208 }
6209#ifdef SQLITE_WIN32_HAS_ANSI
6210 else{
drh153c62c2007-08-24 03:51:336211 char *zTemp;
mistachkin7ea11af2012-09-13 15:24:296212 nByte = osGetFullPathNameA((char*)zConverted, 0, 0, 0);
6213 if( nByte==0 ){
mistachkin7ea11af2012-09-13 15:24:296214 sqlite3_free(zConverted);
mistachkin9f11ef12013-08-31 02:48:566215 return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(),
6216 "winFullPathname3", zRelative);
mistachkin7ea11af2012-09-13 15:24:296217 }
drhef86b942025-02-17 17:33:146218 zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) + 3*sizeof(zTemp[0]) );
drh153c62c2007-08-24 03:51:336219 if( zTemp==0 ){
mistachkin5f075382011-11-11 23:31:046220 sqlite3_free(zConverted);
mistachkinfad30392016-02-13 23:43:466221 return SQLITE_IOERR_NOMEM_BKPT;
drh153c62c2007-08-24 03:51:336222 }
drhef86b942025-02-17 17:33:146223 nByte = osGetFullPathNameA((char*)zConverted, nByte+3, zTemp, 0);
mistachkin7ea11af2012-09-13 15:24:296224 if( nByte==0 ){
mistachkin7ea11af2012-09-13 15:24:296225 sqlite3_free(zConverted);
6226 sqlite3_free(zTemp);
mistachkin9f11ef12013-08-31 02:48:566227 return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(),
6228 "winFullPathname4", zRelative);
mistachkin7ea11af2012-09-13 15:24:296229 }
mistachkin5f075382011-11-11 23:31:046230 sqlite3_free(zConverted);
mistachkin12931202016-04-04 02:05:466231 zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI());
mistachkin5f075382011-11-11 23:31:046232 sqlite3_free(zTemp);
drh153c62c2007-08-24 03:51:336233 }
drhd52ee722012-03-02 00:00:476234#endif
drh153c62c2007-08-24 03:51:336235 if( zOut ){
stephan42e5ceb2025-03-10 15:15:136236#ifdef __CYGWIN__
6237 if( memcmp(zOut, "\\\\?\\", 4) ){
6238 sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut);
6239 }else if( memcmp(zOut+4, "UNC\\", 4) ){
6240 sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut+4);
6241 }else{
6242 char *p = zOut+6;
6243 *p = '\\';
6244 if( osGetcwd ){
6245 /* On Cygwin, UNC paths use forward slashes */
6246 while( *p ){
6247 if( *p=='\\' ) *p = '/';
6248 ++p;
6249 }
6250 }
6251 sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut+6);
6252 }
6253#else
mistachkina112d142012-03-14 00:44:016254 sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut);
stephan42e5ceb2025-03-10 15:15:136255#endif /* __CYGWIN__ */
mistachkin5f075382011-11-11 23:31:046256 sqlite3_free(zOut);
drh153c62c2007-08-24 03:51:336257 return SQLITE_OK;
6258 }else{
mistachkinfad30392016-02-13 23:43:466259 return SQLITE_IOERR_NOMEM_BKPT;
drh153c62c2007-08-24 03:51:336260 }
6261#endif
6262}
drhfee64312022-09-02 11:12:166263static int winFullPathname(
6264 sqlite3_vfs *pVfs, /* Pointer to vfs object */
6265 const char *zRelative, /* Possibly relative input path */
6266 int nFull, /* Size of output buffer in bytes */
6267 char *zFull /* Output buffer */
6268){
6269 int rc;
mistachkinbdb63682022-09-09 17:50:296270 MUTEX_LOGIC( sqlite3_mutex *pMutex; )
6271 MUTEX_LOGIC( pMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR); )
drhfee64312022-09-02 11:12:166272 sqlite3_mutex_enter(pMutex);
6273 rc = winFullPathnameNoMutex(pVfs, zRelative, nFull, zFull);
6274 sqlite3_mutex_leave(pMutex);
6275 return rc;
6276}
drh153c62c2007-08-24 03:51:336277
6278#ifndef SQLITE_OMIT_LOAD_EXTENSION
drh761df872006-12-21 01:29:226279/*
6280** Interfaces for opening a shared library, finding entry points
6281** within the shared library, and closing the shared library.
6282*/
drh153c62c2007-08-24 03:51:336283static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
drh761df872006-12-21 01:29:226284 HANDLE h;
mistachkind95a3d32013-08-30 21:52:386285 void *zConverted = winConvertFromUtf8Filename(zFilename);
drh761df872006-12-21 01:29:226286 UNUSED_PARAMETER(pVfs);
drh761df872006-12-21 01:29:226287 if( zConverted==0 ){
mistachkin1925a2e2014-02-24 21:20:256288 OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0));
drh761df872006-12-21 01:29:226289 return 0;
6290 }
mistachkinb324bc72013-08-28 02:37:296291 if( osIsNT() ){
mistachkindf562d52012-03-13 01:16:576292#if SQLITE_OS_WINRT
mistachkin5483f772012-03-07 20:11:476293 h = osLoadPackagedLibrary((LPCWSTR)zConverted, 0);
6294#else
mistachkin318507b2011-11-11 22:08:546295 h = osLoadLibraryW((LPCWSTR)zConverted);
mistachkin5483f772012-03-07 20:11:476296#endif
drh761df872006-12-21 01:29:226297 }
drhd52ee722012-03-02 00:00:476298#ifdef SQLITE_WIN32_HAS_ANSI
6299 else{
6300 h = osLoadLibraryA((char*)zConverted);
6301 }
6302#endif
mistachkin1925a2e2014-02-24 21:20:256303 OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)h));
mistachkin5f075382011-11-11 23:31:046304 sqlite3_free(zConverted);
drh761df872006-12-21 01:29:226305 return (void*)h;
drh761df872006-12-21 01:29:226306}
drh153c62c2007-08-24 03:51:336307static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
drh1bd10f82008-12-10 21:19:566308 UNUSED_PARAMETER(pVfs);
mistachkinb324bc72013-08-28 02:37:296309 winGetLastErrorMsg(osGetLastError(), nBuf, zBufOut);
drh153c62c2007-08-24 03:51:336310}
drh14880522013-03-01 23:24:046311static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){
mistachkin151d05c2014-02-24 21:42:336312 FARPROC proc;
drh1bd10f82008-12-10 21:19:566313 UNUSED_PARAMETER(pVfs);
mistachkin151d05c2014-02-24 21:42:336314 proc = osGetProcAddressA((HANDLE)pH, zSym);
6315 OSTRACE(("DLSYM handle=%p, symbol=%s, address=%p\n",
6316 (void*)pH, zSym, (void*)proc));
6317 return (void(*)(void))proc;
drh761df872006-12-21 01:29:226318}
drh134c4ff2011-10-13 14:05:326319static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
drh1bd10f82008-12-10 21:19:566320 UNUSED_PARAMETER(pVfs);
mistachkin318507b2011-11-11 22:08:546321 osFreeLibrary((HANDLE)pHandle);
mistachkin1925a2e2014-02-24 21:20:256322 OSTRACE(("DLCLOSE handle=%p\n", (void*)pHandle));
drh761df872006-12-21 01:29:226323}
drh153c62c2007-08-24 03:51:336324#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
6325 #define winDlOpen 0
6326 #define winDlError 0
6327 #define winDlSym 0
6328 #define winDlClose 0
6329#endif
6330
drh8eb37902016-02-15 20:41:566331/* State information for the randomness gatherer. */
6332typedef struct EntropyGatherer EntropyGatherer;
6333struct EntropyGatherer {
6334 unsigned char *a; /* Gather entropy into this buffer */
6335 int na; /* Size of a[] in bytes */
6336 int i; /* XOR next input into a[i] */
6337 int nXor; /* Number of XOR operations done */
6338};
6339
6340#if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS)
6341/* Mix sz bytes of entropy into p. */
6342static void xorMemory(EntropyGatherer *p, unsigned char *x, int sz){
6343 int j, k;
6344 for(j=0, k=p->i; j<sz; j++){
6345 p->a[k++] ^= x[j];
6346 if( k>=p->na ) k = 0;
6347 }
6348 p->i = k;
6349 p->nXor += sz;
6350}
mistachkinb71aef32016-02-15 22:37:186351#endif /* !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS) */
drh761df872006-12-21 01:29:226352
drh0ccebe72005-06-07 22:22:506353/*
drh153c62c2007-08-24 03:51:336354** Write up to nBuf bytes of randomness into zBuf.
drhbbd42a62004-05-22 17:41:586355*/
drh153c62c2007-08-24 03:51:336356static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
drh6a412b82015-04-30 12:31:496357#if defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS)
drh8eb37902016-02-15 20:41:566358 UNUSED_PARAMETER(pVfs);
shanec7b7f1a2008-11-19 21:35:466359 memset(zBuf, 0, nBuf);
drh8eb37902016-02-15 20:41:566360 return nBuf;
shanec7b7f1a2008-11-19 21:35:466361#else
drh8eb37902016-02-15 20:41:566362 EntropyGatherer e;
6363 UNUSED_PARAMETER(pVfs);
6364 memset(zBuf, 0, nBuf);
6365 e.a = (unsigned char*)zBuf;
6366 e.na = nBuf;
6367 e.nXor = 0;
6368 e.i = 0;
6369 {
drhd1a79312007-09-03 13:06:116370 SYSTEMTIME x;
mistachkin318507b2011-11-11 22:08:546371 osGetSystemTime(&x);
mistachkinb71aef32016-02-15 22:37:186372 xorMemory(&e, (unsigned char*)&x, sizeof(SYSTEMTIME));
drh153c62c2007-08-24 03:51:336373 }
drh8eb37902016-02-15 20:41:566374 {
mistachkin318507b2011-11-11 22:08:546375 DWORD pid = osGetCurrentProcessId();
mistachkinb71aef32016-02-15 22:37:186376 xorMemory(&e, (unsigned char*)&pid, sizeof(DWORD));
drhd1a79312007-09-03 13:06:116377 }
mistachkindf562d52012-03-13 01:16:576378#if SQLITE_OS_WINRT
drh8eb37902016-02-15 20:41:566379 {
mistachkindf562d52012-03-13 01:16:576380 ULONGLONG cnt = osGetTickCount64();
mistachkinb71aef32016-02-15 22:37:186381 xorMemory(&e, (unsigned char*)&cnt, sizeof(ULONGLONG));
mistachkindf562d52012-03-13 01:16:576382 }
6383#else
drh8eb37902016-02-15 20:41:566384 {
mistachkin318507b2011-11-11 22:08:546385 DWORD cnt = osGetTickCount();
mistachkinb71aef32016-02-15 22:37:186386 xorMemory(&e, (unsigned char*)&cnt, sizeof(DWORD));
drhd1a79312007-09-03 13:06:116387 }
mistachkinb71aef32016-02-15 22:37:186388#endif /* SQLITE_OS_WINRT */
drh8eb37902016-02-15 20:41:566389 {
drhd1a79312007-09-03 13:06:116390 LARGE_INTEGER i;
mistachkin318507b2011-11-11 22:08:546391 osQueryPerformanceCounter(&i);
mistachkinb71aef32016-02-15 22:37:186392 xorMemory(&e, (unsigned char*)&i, sizeof(LARGE_INTEGER));
drhd1a79312007-09-03 13:06:116393 }
mistachkine45e0fb2015-01-21 00:48:466394#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
drh8eb37902016-02-15 20:41:566395 {
mistachkine45e0fb2015-01-21 00:48:466396 UUID id;
6397 memset(&id, 0, sizeof(UUID));
6398 osUuidCreate(&id);
drh8eb37902016-02-15 20:41:566399 xorMemory(&e, (unsigned char*)&id, sizeof(UUID));
mistachkine45e0fb2015-01-21 00:48:466400 memset(&id, 0, sizeof(UUID));
6401 osUuidCreateSequential(&id);
drh8eb37902016-02-15 20:41:566402 xorMemory(&e, (unsigned char*)&id, sizeof(UUID));
mistachkine45e0fb2015-01-21 00:48:466403 }
mistachkinb71aef32016-02-15 22:37:186404#endif /* !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID */
drh8eb37902016-02-15 20:41:566405 return e.nXor>nBuf ? nBuf : e.nXor;
mistachkin0ead47d2016-02-15 22:28:506406#endif /* defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS) */
drhbbd42a62004-05-22 17:41:586407}
6408
drh153c62c2007-08-24 03:51:336409
drhbbd42a62004-05-22 17:41:586410/*
6411** Sleep for a little while. Return the amount of time slept.
6412*/
drh153c62c2007-08-24 03:51:336413static int winSleep(sqlite3_vfs *pVfs, int microsec){
mistachkinf4f327c2012-03-13 03:35:076414 sqlite3_win32_sleep((microsec+999)/1000);
drh1bd10f82008-12-10 21:19:566415 UNUSED_PARAMETER(pVfs);
drh153c62c2007-08-24 03:51:336416 return ((microsec+999)/1000)*1000;
drhbbd42a62004-05-22 17:41:586417}
6418
6419/*
shaneh04882a92010-05-11 02:49:396420** The following variable, if set to a non-zero value, is interpreted as
6421** the number of seconds since 1970 and is used to set the result of
6422** sqlite3OsCurrentTime() during testing.
drhbbd42a62004-05-22 17:41:586423*/
6424#ifdef SQLITE_TEST
shaneh04882a92010-05-11 02:49:396425int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */
drhbbd42a62004-05-22 17:41:586426#endif
6427
6428/*
shaneh04882a92010-05-11 02:49:396429** Find the current time (in Universal Coordinated Time). Write into *piNow
6430** the current time and date as a Julian Day number times 86_400_000. In
6431** other words, write into *piNow the number of milliseconds since the Julian
6432** epoch of noon in Greenwich on November 24, 4714 B.C according to the
6433** proleptic Gregorian calendar.
6434**
mistachkin17835a52014-08-06 03:06:016435** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
drh31702252011-10-12 23:13:436436** cannot be found.
drhbbd42a62004-05-22 17:41:586437*/
shaneh04882a92010-05-11 02:49:396438static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
mistachkin17835a52014-08-06 03:06:016439 /* FILETIME structure is a 64-bit value representing the number of
6440 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
drhbbd42a62004-05-22 17:41:586441 */
shaneh04882a92010-05-11 02:49:396442 FILETIME ft;
6443 static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000;
6444#ifdef SQLITE_TEST
6445 static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
6446#endif
shaneb08a67a2009-03-31 03:41:566447 /* 2^32 - to avoid use of LL and warnings in gcc */
mistachkin17835a52014-08-06 03:06:016448 static const sqlite3_int64 max32BitValue =
drh14880522013-03-01 23:24:046449 (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 +
6450 (sqlite3_int64)294967296;
drh5c905d62009-03-30 12:42:456451
danielk197729bafea2008-06-26 10:41:196452#if SQLITE_OS_WINCE
drhcc78fea2006-01-06 16:17:056453 SYSTEMTIME time;
mistachkin318507b2011-11-11 22:08:546454 osGetSystemTime(&time);
shane820800d2008-07-22 05:32:036455 /* if SystemTimeToFileTime() fails, it returns zero. */
mistachkin318507b2011-11-11 22:08:546456 if (!osSystemTimeToFileTime(&time,&ft)){
drh31702252011-10-12 23:13:436457 return SQLITE_ERROR;
shane820800d2008-07-22 05:32:036458 }
drhcc78fea2006-01-06 16:17:056459#else
mistachkin318507b2011-11-11 22:08:546460 osGetSystemTimeAsFileTime( &ft );
drhcc78fea2006-01-06 16:17:056461#endif
shaneh04882a92010-05-11 02:49:396462
6463 *piNow = winFiletimeEpoch +
mistachkin17835a52014-08-06 03:06:016464 ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) +
drhb316cb22010-06-23 15:18:116465 (sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000;
shaneh04882a92010-05-11 02:49:396466
drhbbd42a62004-05-22 17:41:586467#ifdef SQLITE_TEST
6468 if( sqlite3_current_time ){
shaneh04882a92010-05-11 02:49:396469 *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
drhbbd42a62004-05-22 17:41:586470 }
6471#endif
shaneh04882a92010-05-11 02:49:396472 UNUSED_PARAMETER(pVfs);
drh31702252011-10-12 23:13:436473 return SQLITE_OK;
drhbbd42a62004-05-22 17:41:586474}
6475
shane820800d2008-07-22 05:32:036476/*
shaneh04882a92010-05-11 02:49:396477** Find the current time (in Universal Coordinated Time). Write the
6478** current time and date as a Julian Day number into *prNow and
6479** return 0. Return 1 if the time and date cannot be found.
6480*/
drh134c4ff2011-10-13 14:05:326481static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
shaneh04882a92010-05-11 02:49:396482 int rc;
6483 sqlite3_int64 i;
6484 rc = winCurrentTimeInt64(pVfs, &i);
6485 if( !rc ){
6486 *prNow = i/86400000.0;
6487 }
6488 return rc;
6489}
6490
6491/*
shane820800d2008-07-22 05:32:036492** The idea is that this function works like a combination of
mistachkin318507b2011-11-11 22:08:546493** GetLastError() and FormatMessage() on Windows (or errno and
6494** strerror_r() on Unix). After an error is returned by an OS
shane820800d2008-07-22 05:32:036495** function, SQLite calls this function with zBuf pointing to
6496** a buffer of nBuf bytes. The OS layer should populate the
6497** buffer with a nul-terminated UTF-8 encoded error message
shanebe217792009-03-05 04:20:316498** describing the last IO error to have occurred within the calling
shane820800d2008-07-22 05:32:036499** thread.
6500**
6501** If the error message is too large for the supplied buffer,
6502** it should be truncated. The return value of xGetLastError
6503** is zero if the error message fits in the buffer, or non-zero
6504** otherwise (if the message was truncated). If non-zero is returned,
6505** then it is not necessary to include the nul-terminator character
6506** in the output buffer.
6507**
6508** Not supplying an error message will have no adverse effect
6509** on SQLite. It is fine to have an implementation that never
6510** returns an error message:
6511**
6512** int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
6513** assert(zBuf[0]=='\0');
6514** return 0;
6515** }
6516**
6517** However if an error message is supplied, it will be incorporated
6518** by sqlite into the error message available to the user using
6519** sqlite3_errmsg(), possibly making IO errors easier to debug.
6520*/
danielk1977bcb97fe2008-06-06 15:49:296521static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
drh762e32b2016-03-17 19:28:196522 DWORD e = osGetLastError();
drh1bd10f82008-12-10 21:19:566523 UNUSED_PARAMETER(pVfs);
drh762e32b2016-03-17 19:28:196524 if( nBuf>0 ) winGetLastErrorMsg(e, nBuf, zBuf);
6525 return e;
danielk1977bcb97fe2008-06-06 15:49:296526}
drhb4bc7052006-01-11 23:40:336527
6528/*
danielk1977c0fa4c52008-06-25 17:19:006529** Initialize and deinitialize the operating system interface.
danielk197713a68c32005-12-15 10:11:306530*/
danielk1977c0fa4c52008-06-25 17:19:006531int sqlite3_os_init(void){
drh153c62c2007-08-24 03:51:336532 static sqlite3_vfs winVfs = {
mistachkin1e754832016-07-08 21:14:376533 3, /* iVersion */
6534 sizeof(winFile), /* szOsFile */
mistachkin31706a22013-08-26 20:45:506535 SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */
mistachkin1e754832016-07-08 21:14:376536 0, /* pNext */
6537 "win32", /* zName */
6538 &winAppData, /* pAppData */
6539 winOpen, /* xOpen */
6540 winDelete, /* xDelete */
6541 winAccess, /* xAccess */
6542 winFullPathname, /* xFullPathname */
6543 winDlOpen, /* xDlOpen */
6544 winDlError, /* xDlError */
6545 winDlSym, /* xDlSym */
6546 winDlClose, /* xDlClose */
6547 winRandomness, /* xRandomness */
6548 winSleep, /* xSleep */
6549 winCurrentTime, /* xCurrentTime */
6550 winGetLastError, /* xGetLastError */
6551 winCurrentTimeInt64, /* xCurrentTimeInt64 */
6552 winSetSystemCall, /* xSetSystemCall */
6553 winGetSystemCall, /* xGetSystemCall */
6554 winNextSystemCall, /* xNextSystemCall */
drh153c62c2007-08-24 03:51:336555 };
mistachkin37418272013-08-28 05:49:396556#if defined(SQLITE_WIN32_HAS_WIDE)
6557 static sqlite3_vfs winLongPathVfs = {
mistachkin1e754832016-07-08 21:14:376558 3, /* iVersion */
6559 sizeof(winFile), /* szOsFile */
mistachkin37418272013-08-28 05:49:396560 SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */
mistachkin1e754832016-07-08 21:14:376561 0, /* pNext */
6562 "win32-longpath", /* zName */
6563 &winAppData, /* pAppData */
6564 winOpen, /* xOpen */
6565 winDelete, /* xDelete */
6566 winAccess, /* xAccess */
6567 winFullPathname, /* xFullPathname */
6568 winDlOpen, /* xDlOpen */
6569 winDlError, /* xDlError */
6570 winDlSym, /* xDlSym */
6571 winDlClose, /* xDlClose */
6572 winRandomness, /* xRandomness */
6573 winSleep, /* xSleep */
6574 winCurrentTime, /* xCurrentTime */
6575 winGetLastError, /* xGetLastError */
6576 winCurrentTimeInt64, /* xCurrentTimeInt64 */
6577 winSetSystemCall, /* xSetSystemCall */
6578 winGetSystemCall, /* xGetSystemCall */
6579 winNextSystemCall, /* xNextSystemCall */
6580 };
6581#endif
6582 static sqlite3_vfs winNolockVfs = {
6583 3, /* iVersion */
6584 sizeof(winFile), /* szOsFile */
6585 SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */
6586 0, /* pNext */
6587 "win32-none", /* zName */
6588 &winNolockAppData, /* pAppData */
6589 winOpen, /* xOpen */
6590 winDelete, /* xDelete */
6591 winAccess, /* xAccess */
6592 winFullPathname, /* xFullPathname */
6593 winDlOpen, /* xDlOpen */
6594 winDlError, /* xDlError */
6595 winDlSym, /* xDlSym */
6596 winDlClose, /* xDlClose */
6597 winRandomness, /* xRandomness */
6598 winSleep, /* xSleep */
6599 winCurrentTime, /* xCurrentTime */
6600 winGetLastError, /* xGetLastError */
6601 winCurrentTimeInt64, /* xCurrentTimeInt64 */
6602 winSetSystemCall, /* xSetSystemCall */
6603 winGetSystemCall, /* xGetSystemCall */
6604 winNextSystemCall, /* xNextSystemCall */
6605 };
6606#if defined(SQLITE_WIN32_HAS_WIDE)
6607 static sqlite3_vfs winLongPathNolockVfs = {
6608 3, /* iVersion */
6609 sizeof(winFile), /* szOsFile */
6610 SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */
6611 0, /* pNext */
6612 "win32-longpath-none", /* zName */
6613 &winNolockAppData, /* pAppData */
6614 winOpen, /* xOpen */
6615 winDelete, /* xDelete */
6616 winAccess, /* xAccess */
6617 winFullPathname, /* xFullPathname */
6618 winDlOpen, /* xDlOpen */
6619 winDlError, /* xDlError */
6620 winDlSym, /* xDlSym */
6621 winDlClose, /* xDlClose */
6622 winRandomness, /* xRandomness */
6623 winSleep, /* xSleep */
6624 winCurrentTime, /* xCurrentTime */
6625 winGetLastError, /* xGetLastError */
6626 winCurrentTimeInt64, /* xCurrentTimeInt64 */
6627 winSetSystemCall, /* xSetSystemCall */
6628 winGetSystemCall, /* xGetSystemCall */
6629 winNextSystemCall, /* xNextSystemCall */
mistachkin37418272013-08-28 05:49:396630 };
6631#endif
dane1ab2192009-08-17 15:16:196632
mistachkin318507b2011-11-11 22:08:546633 /* Double-check that the aSyscall[] array has been constructed
6634 ** correctly. See ticket [bb3a86e890c8e96ab] */
stephan7b9407a2025-03-07 06:54:046635 assert( ArraySize(aSyscall)==89 );
drh7acec682012-03-01 21:19:396636
shaneh420398c2010-09-03 04:29:306637 /* get memory map allocation granularity */
6638 memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
mistachkindf562d52012-03-13 01:16:576639#if SQLITE_OS_WINRT
6640 osGetNativeSystemInfo(&winSysInfo);
6641#else
mistachkin318507b2011-11-11 22:08:546642 osGetSystemInfo(&winSysInfo);
mistachkindf562d52012-03-13 01:16:576643#endif
mistachkindaf9a5a2013-03-23 09:56:396644 assert( winSysInfo.dwAllocationGranularity>0 );
6645 assert( winSysInfo.dwPageSize>0 );
shaneh420398c2010-09-03 04:29:306646
danielk1977c0fa4c52008-06-25 17:19:006647 sqlite3_vfs_register(&winVfs, 1);
mistachkin37418272013-08-28 05:49:396648
6649#if defined(SQLITE_WIN32_HAS_WIDE)
6650 sqlite3_vfs_register(&winLongPathVfs, 0);
6651#endif
6652
mistachkin1e754832016-07-08 21:14:376653 sqlite3_vfs_register(&winNolockVfs, 0);
6654
6655#if defined(SQLITE_WIN32_HAS_WIDE)
6656 sqlite3_vfs_register(&winLongPathNolockVfs, 0);
6657#endif
6658
mistachkinbc6b8d72018-02-05 21:02:476659#ifndef SQLITE_OMIT_WAL
mistachkin435666e2018-02-05 20:42:506660 winBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
mistachkinbc6b8d72018-02-05 21:02:476661#endif
6662
mistachkin17835a52014-08-06 03:06:016663 return SQLITE_OK;
danielk197713a68c32005-12-15 10:11:306664}
mistachkin6c3c1a02011-11-12 03:17:406665
mistachkin17835a52014-08-06 03:06:016666int sqlite3_os_end(void){
drh7acec682012-03-01 21:19:396667#if SQLITE_OS_WINRT
mistachkinc60941f2012-09-13 01:51:026668 if( sleepObj!=NULL ){
mistachkinf4f327c2012-03-13 03:35:076669 osCloseHandle(sleepObj);
6670 sleepObj = NULL;
6671 }
drh7acec682012-03-01 21:19:396672#endif
mistachkinbc6b8d72018-02-05 21:02:476673
6674#ifndef SQLITE_OMIT_WAL
mistachkin435666e2018-02-05 20:42:506675 winBigLock = 0;
mistachkinbc6b8d72018-02-05 21:02:476676#endif
6677
danielk1977c0fa4c52008-06-25 17:19:006678 return SQLITE_OK;
6679}
drh40257ff2008-06-13 18:24:276680
danielk197729bafea2008-06-26 10:41:196681#endif /* SQLITE_OS_WIN */