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