Annotation of embedaddon/sqlite3/src/os_win.c, revision 1.1
1.1 ! misho 1: /*
! 2: ** 2004 May 22
! 3: **
! 4: ** The author disclaims copyright to this source code. In place of
! 5: ** a legal notice, here is a blessing:
! 6: **
! 7: ** May you do good and not evil.
! 8: ** May you find forgiveness for yourself and forgive others.
! 9: ** May you share freely, never taking more than you give.
! 10: **
! 11: ******************************************************************************
! 12: **
! 13: ** This file contains code that is specific to Windows.
! 14: */
! 15: #include "sqliteInt.h"
! 16: #if SQLITE_OS_WIN /* This file is used for Windows only */
! 17:
! 18: #ifdef __CYGWIN__
! 19: # include <sys/cygwin.h>
! 20: #endif
! 21:
! 22: /*
! 23: ** Include code that is common to all os_*.c files
! 24: */
! 25: #include "os_common.h"
! 26:
! 27: /*
! 28: ** Some Microsoft compilers lack this definition.
! 29: */
! 30: #ifndef INVALID_FILE_ATTRIBUTES
! 31: # define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
! 32: #endif
! 33:
! 34: /* Forward references */
! 35: typedef struct winShm winShm; /* A connection to shared-memory */
! 36: typedef struct winShmNode winShmNode; /* A region of shared-memory */
! 37:
! 38: /*
! 39: ** WinCE lacks native support for file locking so we have to fake it
! 40: ** with some code of our own.
! 41: */
! 42: #if SQLITE_OS_WINCE
! 43: typedef struct winceLock {
! 44: int nReaders; /* Number of reader locks obtained */
! 45: BOOL bPending; /* Indicates a pending lock has been obtained */
! 46: BOOL bReserved; /* Indicates a reserved lock has been obtained */
! 47: BOOL bExclusive; /* Indicates an exclusive lock has been obtained */
! 48: } winceLock;
! 49: #endif
! 50:
! 51: /*
! 52: ** The winFile structure is a subclass of sqlite3_file* specific to the win32
! 53: ** portability layer.
! 54: */
! 55: typedef struct winFile winFile;
! 56: struct winFile {
! 57: const sqlite3_io_methods *pMethod; /*** Must be first ***/
! 58: sqlite3_vfs *pVfs; /* The VFS used to open this file */
! 59: HANDLE h; /* Handle for accessing the file */
! 60: u8 locktype; /* Type of lock currently held on this file */
! 61: short sharedLockByte; /* Randomly chosen byte used as a shared lock */
! 62: u8 ctrlFlags; /* Flags. See WINFILE_* below */
! 63: DWORD lastErrno; /* The Windows errno from the last I/O error */
! 64: winShm *pShm; /* Instance of shared memory on this file */
! 65: const char *zPath; /* Full pathname of this file */
! 66: int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */
! 67: #if SQLITE_OS_WINCE
! 68: LPWSTR zDeleteOnClose; /* Name of file to delete when closing */
! 69: HANDLE hMutex; /* Mutex used to control access to shared lock */
! 70: HANDLE hShared; /* Shared memory segment used for locking */
! 71: winceLock local; /* Locks obtained by this instance of winFile */
! 72: winceLock *shared; /* Global shared lock memory for the file */
! 73: #endif
! 74: };
! 75:
! 76: /*
! 77: ** Allowed values for winFile.ctrlFlags
! 78: */
! 79: #define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */
! 80: #define WINFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
! 81:
! 82: /*
! 83: * If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the
! 84: * various Win32 API heap functions instead of our own.
! 85: */
! 86: #ifdef SQLITE_WIN32_MALLOC
! 87: /*
! 88: * The initial size of the Win32-specific heap. This value may be zero.
! 89: */
! 90: #ifndef SQLITE_WIN32_HEAP_INIT_SIZE
! 91: # define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_DEFAULT_CACHE_SIZE) * \
! 92: (SQLITE_DEFAULT_PAGE_SIZE) + 4194304)
! 93: #endif
! 94:
! 95: /*
! 96: * The maximum size of the Win32-specific heap. This value may be zero.
! 97: */
! 98: #ifndef SQLITE_WIN32_HEAP_MAX_SIZE
! 99: # define SQLITE_WIN32_HEAP_MAX_SIZE (0)
! 100: #endif
! 101:
! 102: /*
! 103: * The extra flags to use in calls to the Win32 heap APIs. This value may be
! 104: * zero for the default behavior.
! 105: */
! 106: #ifndef SQLITE_WIN32_HEAP_FLAGS
! 107: # define SQLITE_WIN32_HEAP_FLAGS (0)
! 108: #endif
! 109:
! 110: /*
! 111: ** The winMemData structure stores information required by the Win32-specific
! 112: ** sqlite3_mem_methods implementation.
! 113: */
! 114: typedef struct winMemData winMemData;
! 115: struct winMemData {
! 116: #ifndef NDEBUG
! 117: u32 magic; /* Magic number to detect structure corruption. */
! 118: #endif
! 119: HANDLE hHeap; /* The handle to our heap. */
! 120: BOOL bOwned; /* Do we own the heap (i.e. destroy it on shutdown)? */
! 121: };
! 122:
! 123: #ifndef NDEBUG
! 124: #define WINMEM_MAGIC 0x42b2830b
! 125: #endif
! 126:
! 127: static struct winMemData win_mem_data = {
! 128: #ifndef NDEBUG
! 129: WINMEM_MAGIC,
! 130: #endif
! 131: NULL, FALSE
! 132: };
! 133:
! 134: #ifndef NDEBUG
! 135: #define winMemAssertMagic() assert( win_mem_data.magic==WINMEM_MAGIC )
! 136: #else
! 137: #define winMemAssertMagic()
! 138: #endif
! 139:
! 140: #define winMemGetHeap() win_mem_data.hHeap
! 141:
! 142: static void *winMemMalloc(int nBytes);
! 143: static void winMemFree(void *pPrior);
! 144: static void *winMemRealloc(void *pPrior, int nBytes);
! 145: static int winMemSize(void *p);
! 146: static int winMemRoundup(int n);
! 147: static int winMemInit(void *pAppData);
! 148: static void winMemShutdown(void *pAppData);
! 149:
! 150: const sqlite3_mem_methods *sqlite3MemGetWin32(void);
! 151: #endif /* SQLITE_WIN32_MALLOC */
! 152:
! 153: /*
! 154: ** The following variable is (normally) set once and never changes
! 155: ** thereafter. It records whether the operating system is Win9x
! 156: ** or WinNT.
! 157: **
! 158: ** 0: Operating system unknown.
! 159: ** 1: Operating system is Win9x.
! 160: ** 2: Operating system is WinNT.
! 161: **
! 162: ** In order to facilitate testing on a WinNT system, the test fixture
! 163: ** can manually set this value to 1 to emulate Win98 behavior.
! 164: */
! 165: #ifdef SQLITE_TEST
! 166: int sqlite3_os_type = 0;
! 167: #else
! 168: static int sqlite3_os_type = 0;
! 169: #endif
! 170:
! 171: /*
! 172: ** Many system calls are accessed through pointer-to-functions so that
! 173: ** they may be overridden at runtime to facilitate fault injection during
! 174: ** testing and sandboxing. The following array holds the names and pointers
! 175: ** to all overrideable system calls.
! 176: */
! 177: #if !SQLITE_OS_WINCE
! 178: # define SQLITE_WIN32_HAS_ANSI
! 179: #endif
! 180:
! 181: #if SQLITE_OS_WINCE || SQLITE_OS_WINNT
! 182: # define SQLITE_WIN32_HAS_WIDE
! 183: #endif
! 184:
! 185: #ifndef SYSCALL
! 186: # define SYSCALL sqlite3_syscall_ptr
! 187: #endif
! 188:
! 189: #if SQLITE_OS_WINCE
! 190: /*
! 191: ** These macros are necessary because Windows CE does not natively support the
! 192: ** Win32 APIs LockFile, UnlockFile, and LockFileEx.
! 193: */
! 194:
! 195: # define LockFile(a,b,c,d,e) winceLockFile(&a, b, c, d, e)
! 196: # define UnlockFile(a,b,c,d,e) winceUnlockFile(&a, b, c, d, e)
! 197: # define LockFileEx(a,b,c,d,e,f) winceLockFileEx(&a, b, c, d, e, f)
! 198:
! 199: /*
! 200: ** These are the special syscall hacks for Windows CE. The locking related
! 201: ** defines here refer to the macros defined just above.
! 202: */
! 203:
! 204: # define osAreFileApisANSI() 1
! 205: # define osLockFile LockFile
! 206: # define osUnlockFile UnlockFile
! 207: # define osLockFileEx LockFileEx
! 208: #endif
! 209:
! 210: static struct win_syscall {
! 211: const char *zName; /* Name of the sytem call */
! 212: sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
! 213: sqlite3_syscall_ptr pDefault; /* Default value */
! 214: } aSyscall[] = {
! 215: #if !SQLITE_OS_WINCE
! 216: { "AreFileApisANSI", (SYSCALL)AreFileApisANSI, 0 },
! 217:
! 218: #define osAreFileApisANSI ((BOOL(WINAPI*)(VOID))aSyscall[0].pCurrent)
! 219: #else
! 220: { "AreFileApisANSI", (SYSCALL)0, 0 },
! 221: #endif
! 222:
! 223: #if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
! 224: { "CharLowerW", (SYSCALL)CharLowerW, 0 },
! 225: #else
! 226: { "CharLowerW", (SYSCALL)0, 0 },
! 227: #endif
! 228:
! 229: #define osCharLowerW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[1].pCurrent)
! 230:
! 231: #if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
! 232: { "CharUpperW", (SYSCALL)CharUpperW, 0 },
! 233: #else
! 234: { "CharUpperW", (SYSCALL)0, 0 },
! 235: #endif
! 236:
! 237: #define osCharUpperW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[2].pCurrent)
! 238:
! 239: { "CloseHandle", (SYSCALL)CloseHandle, 0 },
! 240:
! 241: #define osCloseHandle ((BOOL(WINAPI*)(HANDLE))aSyscall[3].pCurrent)
! 242:
! 243: #if defined(SQLITE_WIN32_HAS_ANSI)
! 244: { "CreateFileA", (SYSCALL)CreateFileA, 0 },
! 245: #else
! 246: { "CreateFileA", (SYSCALL)0, 0 },
! 247: #endif
! 248:
! 249: #define osCreateFileA ((HANDLE(WINAPI*)(LPCSTR,DWORD,DWORD, \
! 250: LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[4].pCurrent)
! 251:
! 252: #if defined(SQLITE_WIN32_HAS_WIDE)
! 253: { "CreateFileW", (SYSCALL)CreateFileW, 0 },
! 254: #else
! 255: { "CreateFileW", (SYSCALL)0, 0 },
! 256: #endif
! 257:
! 258: #define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \
! 259: LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent)
! 260:
! 261: { "CreateFileMapping", (SYSCALL)CreateFileMapping, 0 },
! 262:
! 263: #define osCreateFileMapping ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
! 264: DWORD,DWORD,DWORD,LPCTSTR))aSyscall[6].pCurrent)
! 265:
! 266: #if defined(SQLITE_WIN32_HAS_WIDE)
! 267: { "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 },
! 268: #else
! 269: { "CreateFileMappingW", (SYSCALL)0, 0 },
! 270: #endif
! 271:
! 272: #define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
! 273: DWORD,DWORD,DWORD,LPCWSTR))aSyscall[7].pCurrent)
! 274:
! 275: #if defined(SQLITE_WIN32_HAS_WIDE)
! 276: { "CreateMutexW", (SYSCALL)CreateMutexW, 0 },
! 277: #else
! 278: { "CreateMutexW", (SYSCALL)0, 0 },
! 279: #endif
! 280:
! 281: #define osCreateMutexW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,BOOL, \
! 282: LPCWSTR))aSyscall[8].pCurrent)
! 283:
! 284: #if defined(SQLITE_WIN32_HAS_ANSI)
! 285: { "DeleteFileA", (SYSCALL)DeleteFileA, 0 },
! 286: #else
! 287: { "DeleteFileA", (SYSCALL)0, 0 },
! 288: #endif
! 289:
! 290: #define osDeleteFileA ((BOOL(WINAPI*)(LPCSTR))aSyscall[9].pCurrent)
! 291:
! 292: #if defined(SQLITE_WIN32_HAS_WIDE)
! 293: { "DeleteFileW", (SYSCALL)DeleteFileW, 0 },
! 294: #else
! 295: { "DeleteFileW", (SYSCALL)0, 0 },
! 296: #endif
! 297:
! 298: #define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[10].pCurrent)
! 299:
! 300: #if SQLITE_OS_WINCE
! 301: { "FileTimeToLocalFileTime", (SYSCALL)FileTimeToLocalFileTime, 0 },
! 302: #else
! 303: { "FileTimeToLocalFileTime", (SYSCALL)0, 0 },
! 304: #endif
! 305:
! 306: #define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \
! 307: LPFILETIME))aSyscall[11].pCurrent)
! 308:
! 309: #if SQLITE_OS_WINCE
! 310: { "FileTimeToSystemTime", (SYSCALL)FileTimeToSystemTime, 0 },
! 311: #else
! 312: { "FileTimeToSystemTime", (SYSCALL)0, 0 },
! 313: #endif
! 314:
! 315: #define osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \
! 316: LPSYSTEMTIME))aSyscall[12].pCurrent)
! 317:
! 318: { "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 },
! 319:
! 320: #define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[13].pCurrent)
! 321:
! 322: #if defined(SQLITE_WIN32_HAS_ANSI)
! 323: { "FormatMessageA", (SYSCALL)FormatMessageA, 0 },
! 324: #else
! 325: { "FormatMessageA", (SYSCALL)0, 0 },
! 326: #endif
! 327:
! 328: #define osFormatMessageA ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPSTR, \
! 329: DWORD,va_list*))aSyscall[14].pCurrent)
! 330:
! 331: #if defined(SQLITE_WIN32_HAS_WIDE)
! 332: { "FormatMessageW", (SYSCALL)FormatMessageW, 0 },
! 333: #else
! 334: { "FormatMessageW", (SYSCALL)0, 0 },
! 335: #endif
! 336:
! 337: #define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \
! 338: DWORD,va_list*))aSyscall[15].pCurrent)
! 339:
! 340: { "FreeLibrary", (SYSCALL)FreeLibrary, 0 },
! 341:
! 342: #define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[16].pCurrent)
! 343:
! 344: { "GetCurrentProcessId", (SYSCALL)GetCurrentProcessId, 0 },
! 345:
! 346: #define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[17].pCurrent)
! 347:
! 348: #if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI)
! 349: { "GetDiskFreeSpaceA", (SYSCALL)GetDiskFreeSpaceA, 0 },
! 350: #else
! 351: { "GetDiskFreeSpaceA", (SYSCALL)0, 0 },
! 352: #endif
! 353:
! 354: #define osGetDiskFreeSpaceA ((BOOL(WINAPI*)(LPCSTR,LPDWORD,LPDWORD,LPDWORD, \
! 355: LPDWORD))aSyscall[18].pCurrent)
! 356:
! 357: #if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
! 358: { "GetDiskFreeSpaceW", (SYSCALL)GetDiskFreeSpaceW, 0 },
! 359: #else
! 360: { "GetDiskFreeSpaceW", (SYSCALL)0, 0 },
! 361: #endif
! 362:
! 363: #define osGetDiskFreeSpaceW ((BOOL(WINAPI*)(LPCWSTR,LPDWORD,LPDWORD,LPDWORD, \
! 364: LPDWORD))aSyscall[19].pCurrent)
! 365:
! 366: #if defined(SQLITE_WIN32_HAS_ANSI)
! 367: { "GetFileAttributesA", (SYSCALL)GetFileAttributesA, 0 },
! 368: #else
! 369: { "GetFileAttributesA", (SYSCALL)0, 0 },
! 370: #endif
! 371:
! 372: #define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[20].pCurrent)
! 373:
! 374: #if defined(SQLITE_WIN32_HAS_WIDE)
! 375: { "GetFileAttributesW", (SYSCALL)GetFileAttributesW, 0 },
! 376: #else
! 377: { "GetFileAttributesW", (SYSCALL)0, 0 },
! 378: #endif
! 379:
! 380: #define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[21].pCurrent)
! 381:
! 382: #if defined(SQLITE_WIN32_HAS_WIDE)
! 383: { "GetFileAttributesExW", (SYSCALL)GetFileAttributesExW, 0 },
! 384: #else
! 385: { "GetFileAttributesExW", (SYSCALL)0, 0 },
! 386: #endif
! 387:
! 388: #define osGetFileAttributesExW ((BOOL(WINAPI*)(LPCWSTR,GET_FILEEX_INFO_LEVELS, \
! 389: LPVOID))aSyscall[22].pCurrent)
! 390:
! 391: { "GetFileSize", (SYSCALL)GetFileSize, 0 },
! 392:
! 393: #define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[23].pCurrent)
! 394:
! 395: #if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI)
! 396: { "GetFullPathNameA", (SYSCALL)GetFullPathNameA, 0 },
! 397: #else
! 398: { "GetFullPathNameA", (SYSCALL)0, 0 },
! 399: #endif
! 400:
! 401: #define osGetFullPathNameA ((DWORD(WINAPI*)(LPCSTR,DWORD,LPSTR, \
! 402: LPSTR*))aSyscall[24].pCurrent)
! 403:
! 404: #if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE)
! 405: { "GetFullPathNameW", (SYSCALL)GetFullPathNameW, 0 },
! 406: #else
! 407: { "GetFullPathNameW", (SYSCALL)0, 0 },
! 408: #endif
! 409:
! 410: #define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \
! 411: LPWSTR*))aSyscall[25].pCurrent)
! 412:
! 413: { "GetLastError", (SYSCALL)GetLastError, 0 },
! 414:
! 415: #define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent)
! 416:
! 417: #if SQLITE_OS_WINCE
! 418: /* The GetProcAddressA() routine is only available on Windows CE. */
! 419: { "GetProcAddressA", (SYSCALL)GetProcAddressA, 0 },
! 420: #else
! 421: /* All other Windows platforms expect GetProcAddress() to take
! 422: ** an ANSI string regardless of the _UNICODE setting */
! 423: { "GetProcAddressA", (SYSCALL)GetProcAddress, 0 },
! 424: #endif
! 425:
! 426: #define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \
! 427: LPCSTR))aSyscall[27].pCurrent)
! 428:
! 429: { "GetSystemInfo", (SYSCALL)GetSystemInfo, 0 },
! 430:
! 431: #define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[28].pCurrent)
! 432:
! 433: { "GetSystemTime", (SYSCALL)GetSystemTime, 0 },
! 434:
! 435: #define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[29].pCurrent)
! 436:
! 437: #if !SQLITE_OS_WINCE
! 438: { "GetSystemTimeAsFileTime", (SYSCALL)GetSystemTimeAsFileTime, 0 },
! 439: #else
! 440: { "GetSystemTimeAsFileTime", (SYSCALL)0, 0 },
! 441: #endif
! 442:
! 443: #define osGetSystemTimeAsFileTime ((VOID(WINAPI*)( \
! 444: LPFILETIME))aSyscall[30].pCurrent)
! 445:
! 446: #if defined(SQLITE_WIN32_HAS_ANSI)
! 447: { "GetTempPathA", (SYSCALL)GetTempPathA, 0 },
! 448: #else
! 449: { "GetTempPathA", (SYSCALL)0, 0 },
! 450: #endif
! 451:
! 452: #define osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[31].pCurrent)
! 453:
! 454: #if defined(SQLITE_WIN32_HAS_WIDE)
! 455: { "GetTempPathW", (SYSCALL)GetTempPathW, 0 },
! 456: #else
! 457: { "GetTempPathW", (SYSCALL)0, 0 },
! 458: #endif
! 459:
! 460: #define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[32].pCurrent)
! 461:
! 462: { "GetTickCount", (SYSCALL)GetTickCount, 0 },
! 463:
! 464: #define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent)
! 465:
! 466: #if defined(SQLITE_WIN32_HAS_ANSI)
! 467: { "GetVersionExA", (SYSCALL)GetVersionExA, 0 },
! 468: #else
! 469: { "GetVersionExA", (SYSCALL)0, 0 },
! 470: #endif
! 471:
! 472: #define osGetVersionExA ((BOOL(WINAPI*)( \
! 473: LPOSVERSIONINFOA))aSyscall[34].pCurrent)
! 474:
! 475: { "HeapAlloc", (SYSCALL)HeapAlloc, 0 },
! 476:
! 477: #define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \
! 478: SIZE_T))aSyscall[35].pCurrent)
! 479:
! 480: { "HeapCreate", (SYSCALL)HeapCreate, 0 },
! 481:
! 482: #define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \
! 483: SIZE_T))aSyscall[36].pCurrent)
! 484:
! 485: { "HeapDestroy", (SYSCALL)HeapDestroy, 0 },
! 486:
! 487: #define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[37].pCurrent)
! 488:
! 489: { "HeapFree", (SYSCALL)HeapFree, 0 },
! 490:
! 491: #define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[38].pCurrent)
! 492:
! 493: { "HeapReAlloc", (SYSCALL)HeapReAlloc, 0 },
! 494:
! 495: #define osHeapReAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD,LPVOID, \
! 496: SIZE_T))aSyscall[39].pCurrent)
! 497:
! 498: { "HeapSize", (SYSCALL)HeapSize, 0 },
! 499:
! 500: #define osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \
! 501: LPCVOID))aSyscall[40].pCurrent)
! 502:
! 503: { "HeapValidate", (SYSCALL)HeapValidate, 0 },
! 504:
! 505: #define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \
! 506: LPCVOID))aSyscall[41].pCurrent)
! 507:
! 508: #if defined(SQLITE_WIN32_HAS_ANSI)
! 509: { "LoadLibraryA", (SYSCALL)LoadLibraryA, 0 },
! 510: #else
! 511: { "LoadLibraryA", (SYSCALL)0, 0 },
! 512: #endif
! 513:
! 514: #define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[42].pCurrent)
! 515:
! 516: #if defined(SQLITE_WIN32_HAS_WIDE)
! 517: { "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 },
! 518: #else
! 519: { "LoadLibraryW", (SYSCALL)0, 0 },
! 520: #endif
! 521:
! 522: #define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[43].pCurrent)
! 523:
! 524: { "LocalFree", (SYSCALL)LocalFree, 0 },
! 525:
! 526: #define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[44].pCurrent)
! 527:
! 528: #if !SQLITE_OS_WINCE
! 529: { "LockFile", (SYSCALL)LockFile, 0 },
! 530:
! 531: #define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
! 532: DWORD))aSyscall[45].pCurrent)
! 533: #else
! 534: { "LockFile", (SYSCALL)0, 0 },
! 535: #endif
! 536:
! 537: #if !SQLITE_OS_WINCE
! 538: { "LockFileEx", (SYSCALL)LockFileEx, 0 },
! 539:
! 540: #define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \
! 541: LPOVERLAPPED))aSyscall[46].pCurrent)
! 542: #else
! 543: { "LockFileEx", (SYSCALL)0, 0 },
! 544: #endif
! 545:
! 546: { "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 },
! 547:
! 548: #define osMapViewOfFile ((LPVOID(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
! 549: SIZE_T))aSyscall[47].pCurrent)
! 550:
! 551: { "MultiByteToWideChar", (SYSCALL)MultiByteToWideChar, 0 },
! 552:
! 553: #define osMultiByteToWideChar ((int(WINAPI*)(UINT,DWORD,LPCSTR,int,LPWSTR, \
! 554: int))aSyscall[48].pCurrent)
! 555:
! 556: { "QueryPerformanceCounter", (SYSCALL)QueryPerformanceCounter, 0 },
! 557:
! 558: #define osQueryPerformanceCounter ((BOOL(WINAPI*)( \
! 559: LARGE_INTEGER*))aSyscall[49].pCurrent)
! 560:
! 561: { "ReadFile", (SYSCALL)ReadFile, 0 },
! 562:
! 563: #define osReadFile ((BOOL(WINAPI*)(HANDLE,LPVOID,DWORD,LPDWORD, \
! 564: LPOVERLAPPED))aSyscall[50].pCurrent)
! 565:
! 566: { "SetEndOfFile", (SYSCALL)SetEndOfFile, 0 },
! 567:
! 568: #define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[51].pCurrent)
! 569:
! 570: { "SetFilePointer", (SYSCALL)SetFilePointer, 0 },
! 571:
! 572: #define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \
! 573: DWORD))aSyscall[52].pCurrent)
! 574:
! 575: { "Sleep", (SYSCALL)Sleep, 0 },
! 576:
! 577: #define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[53].pCurrent)
! 578:
! 579: { "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 },
! 580:
! 581: #define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \
! 582: LPFILETIME))aSyscall[54].pCurrent)
! 583:
! 584: #if !SQLITE_OS_WINCE
! 585: { "UnlockFile", (SYSCALL)UnlockFile, 0 },
! 586:
! 587: #define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
! 588: DWORD))aSyscall[55].pCurrent)
! 589: #else
! 590: { "UnlockFile", (SYSCALL)0, 0 },
! 591: #endif
! 592:
! 593: #if !SQLITE_OS_WINCE
! 594: { "UnlockFileEx", (SYSCALL)UnlockFileEx, 0 },
! 595:
! 596: #define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
! 597: LPOVERLAPPED))aSyscall[56].pCurrent)
! 598: #else
! 599: { "UnlockFileEx", (SYSCALL)0, 0 },
! 600: #endif
! 601:
! 602: { "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 },
! 603:
! 604: #define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[57].pCurrent)
! 605:
! 606: { "WideCharToMultiByte", (SYSCALL)WideCharToMultiByte, 0 },
! 607:
! 608: #define osWideCharToMultiByte ((int(WINAPI*)(UINT,DWORD,LPCWSTR,int,LPSTR,int, \
! 609: LPCSTR,LPBOOL))aSyscall[58].pCurrent)
! 610:
! 611: { "WriteFile", (SYSCALL)WriteFile, 0 },
! 612:
! 613: #define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \
! 614: LPOVERLAPPED))aSyscall[59].pCurrent)
! 615:
! 616: }; /* End of the overrideable system calls */
! 617:
! 618: /*
! 619: ** This is the xSetSystemCall() method of sqlite3_vfs for all of the
! 620: ** "win32" VFSes. Return SQLITE_OK opon successfully updating the
! 621: ** system call pointer, or SQLITE_NOTFOUND if there is no configurable
! 622: ** system call named zName.
! 623: */
! 624: static int winSetSystemCall(
! 625: sqlite3_vfs *pNotUsed, /* The VFS pointer. Not used */
! 626: const char *zName, /* Name of system call to override */
! 627: sqlite3_syscall_ptr pNewFunc /* Pointer to new system call value */
! 628: ){
! 629: unsigned int i;
! 630: int rc = SQLITE_NOTFOUND;
! 631:
! 632: UNUSED_PARAMETER(pNotUsed);
! 633: if( zName==0 ){
! 634: /* If no zName is given, restore all system calls to their default
! 635: ** settings and return NULL
! 636: */
! 637: rc = SQLITE_OK;
! 638: for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
! 639: if( aSyscall[i].pDefault ){
! 640: aSyscall[i].pCurrent = aSyscall[i].pDefault;
! 641: }
! 642: }
! 643: }else{
! 644: /* If zName is specified, operate on only the one system call
! 645: ** specified.
! 646: */
! 647: for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
! 648: if( strcmp(zName, aSyscall[i].zName)==0 ){
! 649: if( aSyscall[i].pDefault==0 ){
! 650: aSyscall[i].pDefault = aSyscall[i].pCurrent;
! 651: }
! 652: rc = SQLITE_OK;
! 653: if( pNewFunc==0 ) pNewFunc = aSyscall[i].pDefault;
! 654: aSyscall[i].pCurrent = pNewFunc;
! 655: break;
! 656: }
! 657: }
! 658: }
! 659: return rc;
! 660: }
! 661:
! 662: /*
! 663: ** Return the value of a system call. Return NULL if zName is not a
! 664: ** recognized system call name. NULL is also returned if the system call
! 665: ** is currently undefined.
! 666: */
! 667: static sqlite3_syscall_ptr winGetSystemCall(
! 668: sqlite3_vfs *pNotUsed,
! 669: const char *zName
! 670: ){
! 671: unsigned int i;
! 672:
! 673: UNUSED_PARAMETER(pNotUsed);
! 674: for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
! 675: if( strcmp(zName, aSyscall[i].zName)==0 ) return aSyscall[i].pCurrent;
! 676: }
! 677: return 0;
! 678: }
! 679:
! 680: /*
! 681: ** Return the name of the first system call after zName. If zName==NULL
! 682: ** then return the name of the first system call. Return NULL if zName
! 683: ** is the last system call or if zName is not the name of a valid
! 684: ** system call.
! 685: */
! 686: static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){
! 687: int i = -1;
! 688:
! 689: UNUSED_PARAMETER(p);
! 690: if( zName ){
! 691: for(i=0; i<ArraySize(aSyscall)-1; i++){
! 692: if( strcmp(zName, aSyscall[i].zName)==0 ) break;
! 693: }
! 694: }
! 695: for(i++; i<ArraySize(aSyscall); i++){
! 696: if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
! 697: }
! 698: return 0;
! 699: }
! 700:
! 701: /*
! 702: ** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
! 703: ** or WinCE. Return false (zero) for Win95, Win98, or WinME.
! 704: **
! 705: ** Here is an interesting observation: Win95, Win98, and WinME lack
! 706: ** the LockFileEx() API. But we can still statically link against that
! 707: ** API as long as we don't call it when running Win95/98/ME. A call to
! 708: ** this routine is used to determine if the host is Win95/98/ME or
! 709: ** WinNT/2K/XP so that we will know whether or not we can safely call
! 710: ** the LockFileEx() API.
! 711: */
! 712: #if SQLITE_OS_WINCE
! 713: # define isNT() (1)
! 714: #else
! 715: static int isNT(void){
! 716: if( sqlite3_os_type==0 ){
! 717: OSVERSIONINFOA sInfo;
! 718: sInfo.dwOSVersionInfoSize = sizeof(sInfo);
! 719: osGetVersionExA(&sInfo);
! 720: sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
! 721: }
! 722: return sqlite3_os_type==2;
! 723: }
! 724: #endif /* SQLITE_OS_WINCE */
! 725:
! 726: #ifdef SQLITE_WIN32_MALLOC
! 727: /*
! 728: ** Allocate nBytes of memory.
! 729: */
! 730: static void *winMemMalloc(int nBytes){
! 731: HANDLE hHeap;
! 732: void *p;
! 733:
! 734: winMemAssertMagic();
! 735: hHeap = winMemGetHeap();
! 736: assert( hHeap!=0 );
! 737: assert( hHeap!=INVALID_HANDLE_VALUE );
! 738: #ifdef SQLITE_WIN32_MALLOC_VALIDATE
! 739: assert ( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
! 740: #endif
! 741: assert( nBytes>=0 );
! 742: p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
! 743: if( !p ){
! 744: sqlite3_log(SQLITE_NOMEM, "failed to HeapAlloc %u bytes (%d), heap=%p",
! 745: nBytes, osGetLastError(), (void*)hHeap);
! 746: }
! 747: return p;
! 748: }
! 749:
! 750: /*
! 751: ** Free memory.
! 752: */
! 753: static void winMemFree(void *pPrior){
! 754: HANDLE hHeap;
! 755:
! 756: winMemAssertMagic();
! 757: hHeap = winMemGetHeap();
! 758: assert( hHeap!=0 );
! 759: assert( hHeap!=INVALID_HANDLE_VALUE );
! 760: #ifdef SQLITE_WIN32_MALLOC_VALIDATE
! 761: assert ( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) );
! 762: #endif
! 763: if( !pPrior ) return; /* Passing NULL to HeapFree is undefined. */
! 764: if( !osHeapFree(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ){
! 765: sqlite3_log(SQLITE_NOMEM, "failed to HeapFree block %p (%d), heap=%p",
! 766: pPrior, osGetLastError(), (void*)hHeap);
! 767: }
! 768: }
! 769:
! 770: /*
! 771: ** Change the size of an existing memory allocation
! 772: */
! 773: static void *winMemRealloc(void *pPrior, int nBytes){
! 774: HANDLE hHeap;
! 775: void *p;
! 776:
! 777: winMemAssertMagic();
! 778: hHeap = winMemGetHeap();
! 779: assert( hHeap!=0 );
! 780: assert( hHeap!=INVALID_HANDLE_VALUE );
! 781: #ifdef SQLITE_WIN32_MALLOC_VALIDATE
! 782: assert ( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) );
! 783: #endif
! 784: assert( nBytes>=0 );
! 785: if( !pPrior ){
! 786: p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
! 787: }else{
! 788: p = osHeapReAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior, (SIZE_T)nBytes);
! 789: }
! 790: if( !p ){
! 791: sqlite3_log(SQLITE_NOMEM, "failed to %s %u bytes (%d), heap=%p",
! 792: pPrior ? "HeapReAlloc" : "HeapAlloc", nBytes, osGetLastError(),
! 793: (void*)hHeap);
! 794: }
! 795: return p;
! 796: }
! 797:
! 798: /*
! 799: ** Return the size of an outstanding allocation, in bytes.
! 800: */
! 801: static int winMemSize(void *p){
! 802: HANDLE hHeap;
! 803: SIZE_T n;
! 804:
! 805: winMemAssertMagic();
! 806: hHeap = winMemGetHeap();
! 807: assert( hHeap!=0 );
! 808: assert( hHeap!=INVALID_HANDLE_VALUE );
! 809: #ifdef SQLITE_WIN32_MALLOC_VALIDATE
! 810: assert ( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
! 811: #endif
! 812: if( !p ) return 0;
! 813: n = osHeapSize(hHeap, SQLITE_WIN32_HEAP_FLAGS, p);
! 814: if( n==(SIZE_T)-1 ){
! 815: sqlite3_log(SQLITE_NOMEM, "failed to HeapSize block %p (%d), heap=%p",
! 816: p, osGetLastError(), (void*)hHeap);
! 817: return 0;
! 818: }
! 819: return (int)n;
! 820: }
! 821:
! 822: /*
! 823: ** Round up a request size to the next valid allocation size.
! 824: */
! 825: static int winMemRoundup(int n){
! 826: return n;
! 827: }
! 828:
! 829: /*
! 830: ** Initialize this module.
! 831: */
! 832: static int winMemInit(void *pAppData){
! 833: winMemData *pWinMemData = (winMemData *)pAppData;
! 834:
! 835: if( !pWinMemData ) return SQLITE_ERROR;
! 836: assert( pWinMemData->magic==WINMEM_MAGIC );
! 837: if( !pWinMemData->hHeap ){
! 838: pWinMemData->hHeap = osHeapCreate(SQLITE_WIN32_HEAP_FLAGS,
! 839: SQLITE_WIN32_HEAP_INIT_SIZE,
! 840: SQLITE_WIN32_HEAP_MAX_SIZE);
! 841: if( !pWinMemData->hHeap ){
! 842: sqlite3_log(SQLITE_NOMEM,
! 843: "failed to HeapCreate (%d), flags=%u, initSize=%u, maxSize=%u",
! 844: osGetLastError(), SQLITE_WIN32_HEAP_FLAGS,
! 845: SQLITE_WIN32_HEAP_INIT_SIZE, SQLITE_WIN32_HEAP_MAX_SIZE);
! 846: return SQLITE_NOMEM;
! 847: }
! 848: pWinMemData->bOwned = TRUE;
! 849: }
! 850: assert( pWinMemData->hHeap!=0 );
! 851: assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE );
! 852: #ifdef SQLITE_WIN32_MALLOC_VALIDATE
! 853: assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
! 854: #endif
! 855: return SQLITE_OK;
! 856: }
! 857:
! 858: /*
! 859: ** Deinitialize this module.
! 860: */
! 861: static void winMemShutdown(void *pAppData){
! 862: winMemData *pWinMemData = (winMemData *)pAppData;
! 863:
! 864: if( !pWinMemData ) return;
! 865: if( pWinMemData->hHeap ){
! 866: assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE );
! 867: #ifdef SQLITE_WIN32_MALLOC_VALIDATE
! 868: assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
! 869: #endif
! 870: if( pWinMemData->bOwned ){
! 871: if( !osHeapDestroy(pWinMemData->hHeap) ){
! 872: sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%d), heap=%p",
! 873: osGetLastError(), (void*)pWinMemData->hHeap);
! 874: }
! 875: pWinMemData->bOwned = FALSE;
! 876: }
! 877: pWinMemData->hHeap = NULL;
! 878: }
! 879: }
! 880:
! 881: /*
! 882: ** Populate the low-level memory allocation function pointers in
! 883: ** sqlite3GlobalConfig.m with pointers to the routines in this file. The
! 884: ** arguments specify the block of memory to manage.
! 885: **
! 886: ** This routine is only called by sqlite3_config(), and therefore
! 887: ** is not required to be threadsafe (it is not).
! 888: */
! 889: const sqlite3_mem_methods *sqlite3MemGetWin32(void){
! 890: static const sqlite3_mem_methods winMemMethods = {
! 891: winMemMalloc,
! 892: winMemFree,
! 893: winMemRealloc,
! 894: winMemSize,
! 895: winMemRoundup,
! 896: winMemInit,
! 897: winMemShutdown,
! 898: &win_mem_data
! 899: };
! 900: return &winMemMethods;
! 901: }
! 902:
! 903: void sqlite3MemSetDefault(void){
! 904: sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetWin32());
! 905: }
! 906: #endif /* SQLITE_WIN32_MALLOC */
! 907:
! 908: /*
! 909: ** Convert a UTF-8 string to Microsoft Unicode (UTF-16?).
! 910: **
! 911: ** Space to hold the returned string is obtained from malloc.
! 912: */
! 913: static LPWSTR utf8ToUnicode(const char *zFilename){
! 914: int nChar;
! 915: LPWSTR zWideFilename;
! 916:
! 917: nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
! 918: if( nChar==0 ){
! 919: return 0;
! 920: }
! 921: zWideFilename = sqlite3_malloc( nChar*sizeof(zWideFilename[0]) );
! 922: if( zWideFilename==0 ){
! 923: return 0;
! 924: }
! 925: nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
! 926: nChar);
! 927: if( nChar==0 ){
! 928: sqlite3_free(zWideFilename);
! 929: zWideFilename = 0;
! 930: }
! 931: return zWideFilename;
! 932: }
! 933:
! 934: /*
! 935: ** Convert Microsoft Unicode to UTF-8. Space to hold the returned string is
! 936: ** obtained from sqlite3_malloc().
! 937: */
! 938: static char *unicodeToUtf8(LPCWSTR zWideFilename){
! 939: int nByte;
! 940: char *zFilename;
! 941:
! 942: nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
! 943: if( nByte == 0 ){
! 944: return 0;
! 945: }
! 946: zFilename = sqlite3_malloc( nByte );
! 947: if( zFilename==0 ){
! 948: return 0;
! 949: }
! 950: nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
! 951: 0, 0);
! 952: if( nByte == 0 ){
! 953: sqlite3_free(zFilename);
! 954: zFilename = 0;
! 955: }
! 956: return zFilename;
! 957: }
! 958:
! 959: /*
! 960: ** Convert an ANSI string to Microsoft Unicode, based on the
! 961: ** current codepage settings for file apis.
! 962: **
! 963: ** Space to hold the returned string is obtained
! 964: ** from sqlite3_malloc.
! 965: */
! 966: static LPWSTR mbcsToUnicode(const char *zFilename){
! 967: int nByte;
! 968: LPWSTR zMbcsFilename;
! 969: int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
! 970:
! 971: nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, NULL,
! 972: 0)*sizeof(WCHAR);
! 973: if( nByte==0 ){
! 974: return 0;
! 975: }
! 976: zMbcsFilename = sqlite3_malloc( nByte*sizeof(zMbcsFilename[0]) );
! 977: if( zMbcsFilename==0 ){
! 978: return 0;
! 979: }
! 980: nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename,
! 981: nByte);
! 982: if( nByte==0 ){
! 983: sqlite3_free(zMbcsFilename);
! 984: zMbcsFilename = 0;
! 985: }
! 986: return zMbcsFilename;
! 987: }
! 988:
! 989: /*
! 990: ** Convert Microsoft Unicode to multi-byte character string, based on the
! 991: ** user's ANSI codepage.
! 992: **
! 993: ** Space to hold the returned string is obtained from
! 994: ** sqlite3_malloc().
! 995: */
! 996: static char *unicodeToMbcs(LPCWSTR zWideFilename){
! 997: int nByte;
! 998: char *zFilename;
! 999: int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
! 1000:
! 1001: nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
! 1002: if( nByte == 0 ){
! 1003: return 0;
! 1004: }
! 1005: zFilename = sqlite3_malloc( nByte );
! 1006: if( zFilename==0 ){
! 1007: return 0;
! 1008: }
! 1009: nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename,
! 1010: nByte, 0, 0);
! 1011: if( nByte == 0 ){
! 1012: sqlite3_free(zFilename);
! 1013: zFilename = 0;
! 1014: }
! 1015: return zFilename;
! 1016: }
! 1017:
! 1018: /*
! 1019: ** Convert multibyte character string to UTF-8. Space to hold the
! 1020: ** returned string is obtained from sqlite3_malloc().
! 1021: */
! 1022: char *sqlite3_win32_mbcs_to_utf8(const char *zFilename){
! 1023: char *zFilenameUtf8;
! 1024: LPWSTR zTmpWide;
! 1025:
! 1026: zTmpWide = mbcsToUnicode(zFilename);
! 1027: if( zTmpWide==0 ){
! 1028: return 0;
! 1029: }
! 1030: zFilenameUtf8 = unicodeToUtf8(zTmpWide);
! 1031: sqlite3_free(zTmpWide);
! 1032: return zFilenameUtf8;
! 1033: }
! 1034:
! 1035: /*
! 1036: ** Convert UTF-8 to multibyte character string. Space to hold the
! 1037: ** returned string is obtained from sqlite3_malloc().
! 1038: */
! 1039: char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){
! 1040: char *zFilenameMbcs;
! 1041: LPWSTR zTmpWide;
! 1042:
! 1043: zTmpWide = utf8ToUnicode(zFilename);
! 1044: if( zTmpWide==0 ){
! 1045: return 0;
! 1046: }
! 1047: zFilenameMbcs = unicodeToMbcs(zTmpWide);
! 1048: sqlite3_free(zTmpWide);
! 1049: return zFilenameMbcs;
! 1050: }
! 1051:
! 1052:
! 1053: /*
! 1054: ** The return value of getLastErrorMsg
! 1055: ** is zero if the error message fits in the buffer, or non-zero
! 1056: ** otherwise (if the message was truncated).
! 1057: */
! 1058: static int getLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){
! 1059: /* FormatMessage returns 0 on failure. Otherwise it
! 1060: ** returns the number of TCHARs written to the output
! 1061: ** buffer, excluding the terminating null char.
! 1062: */
! 1063: DWORD dwLen = 0;
! 1064: char *zOut = 0;
! 1065:
! 1066: if( isNT() ){
! 1067: LPWSTR zTempWide = NULL;
! 1068: dwLen = osFormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
! 1069: FORMAT_MESSAGE_FROM_SYSTEM |
! 1070: FORMAT_MESSAGE_IGNORE_INSERTS,
! 1071: NULL,
! 1072: lastErrno,
! 1073: 0,
! 1074: (LPWSTR) &zTempWide,
! 1075: 0,
! 1076: 0);
! 1077: if( dwLen > 0 ){
! 1078: /* allocate a buffer and convert to UTF8 */
! 1079: sqlite3BeginBenignMalloc();
! 1080: zOut = unicodeToUtf8(zTempWide);
! 1081: sqlite3EndBenignMalloc();
! 1082: /* free the system buffer allocated by FormatMessage */
! 1083: osLocalFree(zTempWide);
! 1084: }
! 1085: /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
! 1086: ** Since the ANSI version of these Windows API do not exist for WINCE,
! 1087: ** it's important to not reference them for WINCE builds.
! 1088: */
! 1089: #if SQLITE_OS_WINCE==0
! 1090: }else{
! 1091: char *zTemp = NULL;
! 1092: dwLen = osFormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
! 1093: FORMAT_MESSAGE_FROM_SYSTEM |
! 1094: FORMAT_MESSAGE_IGNORE_INSERTS,
! 1095: NULL,
! 1096: lastErrno,
! 1097: 0,
! 1098: (LPSTR) &zTemp,
! 1099: 0,
! 1100: 0);
! 1101: if( dwLen > 0 ){
! 1102: /* allocate a buffer and convert to UTF8 */
! 1103: sqlite3BeginBenignMalloc();
! 1104: zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
! 1105: sqlite3EndBenignMalloc();
! 1106: /* free the system buffer allocated by FormatMessage */
! 1107: osLocalFree(zTemp);
! 1108: }
! 1109: #endif
! 1110: }
! 1111: if( 0 == dwLen ){
! 1112: sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", lastErrno, lastErrno);
! 1113: }else{
! 1114: /* copy a maximum of nBuf chars to output buffer */
! 1115: sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
! 1116: /* free the UTF8 buffer */
! 1117: sqlite3_free(zOut);
! 1118: }
! 1119: return 0;
! 1120: }
! 1121:
! 1122: /*
! 1123: **
! 1124: ** This function - winLogErrorAtLine() - is only ever called via the macro
! 1125: ** winLogError().
! 1126: **
! 1127: ** This routine is invoked after an error occurs in an OS function.
! 1128: ** It logs a message using sqlite3_log() containing the current value of
! 1129: ** error code and, if possible, the human-readable equivalent from
! 1130: ** FormatMessage.
! 1131: **
! 1132: ** The first argument passed to the macro should be the error code that
! 1133: ** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN).
! 1134: ** The two subsequent arguments should be the name of the OS function that
! 1135: ** failed and the the associated file-system path, if any.
! 1136: */
! 1137: #define winLogError(a,b,c,d) winLogErrorAtLine(a,b,c,d,__LINE__)
! 1138: static int winLogErrorAtLine(
! 1139: int errcode, /* SQLite error code */
! 1140: DWORD lastErrno, /* Win32 last error */
! 1141: const char *zFunc, /* Name of OS function that failed */
! 1142: const char *zPath, /* File path associated with error */
! 1143: int iLine /* Source line number where error occurred */
! 1144: ){
! 1145: char zMsg[500]; /* Human readable error text */
! 1146: int i; /* Loop counter */
! 1147:
! 1148: zMsg[0] = 0;
! 1149: getLastErrorMsg(lastErrno, sizeof(zMsg), zMsg);
! 1150: assert( errcode!=SQLITE_OK );
! 1151: if( zPath==0 ) zPath = "";
! 1152: for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){}
! 1153: zMsg[i] = 0;
! 1154: sqlite3_log(errcode,
! 1155: "os_win.c:%d: (%d) %s(%s) - %s",
! 1156: iLine, lastErrno, zFunc, zPath, zMsg
! 1157: );
! 1158:
! 1159: return errcode;
! 1160: }
! 1161:
! 1162: /*
! 1163: ** The number of times that a ReadFile(), WriteFile(), and DeleteFile()
! 1164: ** will be retried following a locking error - probably caused by
! 1165: ** antivirus software. Also the initial delay before the first retry.
! 1166: ** The delay increases linearly with each retry.
! 1167: */
! 1168: #ifndef SQLITE_WIN32_IOERR_RETRY
! 1169: # define SQLITE_WIN32_IOERR_RETRY 10
! 1170: #endif
! 1171: #ifndef SQLITE_WIN32_IOERR_RETRY_DELAY
! 1172: # define SQLITE_WIN32_IOERR_RETRY_DELAY 25
! 1173: #endif
! 1174: static int win32IoerrRetry = SQLITE_WIN32_IOERR_RETRY;
! 1175: static int win32IoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY;
! 1176:
! 1177: /*
! 1178: ** If a ReadFile() or WriteFile() error occurs, invoke this routine
! 1179: ** to see if it should be retried. Return TRUE to retry. Return FALSE
! 1180: ** to give up with an error.
! 1181: */
! 1182: static int retryIoerr(int *pnRetry, DWORD *pError){
! 1183: DWORD e = osGetLastError();
! 1184: if( *pnRetry>=win32IoerrRetry ){
! 1185: if( pError ){
! 1186: *pError = e;
! 1187: }
! 1188: return 0;
! 1189: }
! 1190: if( e==ERROR_ACCESS_DENIED ||
! 1191: e==ERROR_LOCK_VIOLATION ||
! 1192: e==ERROR_SHARING_VIOLATION ){
! 1193: osSleep(win32IoerrRetryDelay*(1+*pnRetry));
! 1194: ++*pnRetry;
! 1195: return 1;
! 1196: }
! 1197: if( pError ){
! 1198: *pError = e;
! 1199: }
! 1200: return 0;
! 1201: }
! 1202:
! 1203: /*
! 1204: ** Log a I/O error retry episode.
! 1205: */
! 1206: static void logIoerr(int nRetry){
! 1207: if( nRetry ){
! 1208: sqlite3_log(SQLITE_IOERR,
! 1209: "delayed %dms for lock/sharing conflict",
! 1210: win32IoerrRetryDelay*nRetry*(nRetry+1)/2
! 1211: );
! 1212: }
! 1213: }
! 1214:
! 1215: #if SQLITE_OS_WINCE
! 1216: /*************************************************************************
! 1217: ** This section contains code for WinCE only.
! 1218: */
! 1219: /*
! 1220: ** Windows CE does not have a localtime() function. So create a
! 1221: ** substitute.
! 1222: */
! 1223: #include <time.h>
! 1224: struct tm *__cdecl localtime(const time_t *t)
! 1225: {
! 1226: static struct tm y;
! 1227: FILETIME uTm, lTm;
! 1228: SYSTEMTIME pTm;
! 1229: sqlite3_int64 t64;
! 1230: t64 = *t;
! 1231: t64 = (t64 + 11644473600)*10000000;
! 1232: uTm.dwLowDateTime = (DWORD)(t64 & 0xFFFFFFFF);
! 1233: uTm.dwHighDateTime= (DWORD)(t64 >> 32);
! 1234: osFileTimeToLocalFileTime(&uTm,&lTm);
! 1235: osFileTimeToSystemTime(&lTm,&pTm);
! 1236: y.tm_year = pTm.wYear - 1900;
! 1237: y.tm_mon = pTm.wMonth - 1;
! 1238: y.tm_wday = pTm.wDayOfWeek;
! 1239: y.tm_mday = pTm.wDay;
! 1240: y.tm_hour = pTm.wHour;
! 1241: y.tm_min = pTm.wMinute;
! 1242: y.tm_sec = pTm.wSecond;
! 1243: return &y;
! 1244: }
! 1245:
! 1246: #define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
! 1247:
! 1248: /*
! 1249: ** Acquire a lock on the handle h
! 1250: */
! 1251: static void winceMutexAcquire(HANDLE h){
! 1252: DWORD dwErr;
! 1253: do {
! 1254: dwErr = WaitForSingleObject(h, INFINITE);
! 1255: } while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED);
! 1256: }
! 1257: /*
! 1258: ** Release a lock acquired by winceMutexAcquire()
! 1259: */
! 1260: #define winceMutexRelease(h) ReleaseMutex(h)
! 1261:
! 1262: /*
! 1263: ** Create the mutex and shared memory used for locking in the file
! 1264: ** descriptor pFile
! 1265: */
! 1266: static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
! 1267: LPWSTR zTok;
! 1268: LPWSTR zName;
! 1269: BOOL bInit = TRUE;
! 1270:
! 1271: zName = utf8ToUnicode(zFilename);
! 1272: if( zName==0 ){
! 1273: /* out of memory */
! 1274: return FALSE;
! 1275: }
! 1276:
! 1277: /* Initialize the local lockdata */
! 1278: memset(&pFile->local, 0, sizeof(pFile->local));
! 1279:
! 1280: /* Replace the backslashes from the filename and lowercase it
! 1281: ** to derive a mutex name. */
! 1282: zTok = osCharLowerW(zName);
! 1283: for (;*zTok;zTok++){
! 1284: if (*zTok == '\\') *zTok = '_';
! 1285: }
! 1286:
! 1287: /* Create/open the named mutex */
! 1288: pFile->hMutex = osCreateMutexW(NULL, FALSE, zName);
! 1289: if (!pFile->hMutex){
! 1290: pFile->lastErrno = osGetLastError();
! 1291: winLogError(SQLITE_ERROR, pFile->lastErrno, "winceCreateLock1", zFilename);
! 1292: sqlite3_free(zName);
! 1293: return FALSE;
! 1294: }
! 1295:
! 1296: /* Acquire the mutex before continuing */
! 1297: winceMutexAcquire(pFile->hMutex);
! 1298:
! 1299: /* Since the names of named mutexes, semaphores, file mappings etc are
! 1300: ** case-sensitive, take advantage of that by uppercasing the mutex name
! 1301: ** and using that as the shared filemapping name.
! 1302: */
! 1303: osCharUpperW(zName);
! 1304: pFile->hShared = osCreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
! 1305: PAGE_READWRITE, 0, sizeof(winceLock),
! 1306: zName);
! 1307:
! 1308: /* Set a flag that indicates we're the first to create the memory so it
! 1309: ** must be zero-initialized */
! 1310: if (osGetLastError() == ERROR_ALREADY_EXISTS){
! 1311: bInit = FALSE;
! 1312: }
! 1313:
! 1314: sqlite3_free(zName);
! 1315:
! 1316: /* If we succeeded in making the shared memory handle, map it. */
! 1317: if (pFile->hShared){
! 1318: pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared,
! 1319: FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock));
! 1320: /* If mapping failed, close the shared memory handle and erase it */
! 1321: if (!pFile->shared){
! 1322: pFile->lastErrno = osGetLastError();
! 1323: winLogError(SQLITE_ERROR, pFile->lastErrno,
! 1324: "winceCreateLock2", zFilename);
! 1325: osCloseHandle(pFile->hShared);
! 1326: pFile->hShared = NULL;
! 1327: }
! 1328: }
! 1329:
! 1330: /* If shared memory could not be created, then close the mutex and fail */
! 1331: if (pFile->hShared == NULL){
! 1332: winceMutexRelease(pFile->hMutex);
! 1333: osCloseHandle(pFile->hMutex);
! 1334: pFile->hMutex = NULL;
! 1335: return FALSE;
! 1336: }
! 1337:
! 1338: /* Initialize the shared memory if we're supposed to */
! 1339: if (bInit) {
! 1340: memset(pFile->shared, 0, sizeof(winceLock));
! 1341: }
! 1342:
! 1343: winceMutexRelease(pFile->hMutex);
! 1344: return TRUE;
! 1345: }
! 1346:
! 1347: /*
! 1348: ** Destroy the part of winFile that deals with wince locks
! 1349: */
! 1350: static void winceDestroyLock(winFile *pFile){
! 1351: if (pFile->hMutex){
! 1352: /* Acquire the mutex */
! 1353: winceMutexAcquire(pFile->hMutex);
! 1354:
! 1355: /* The following blocks should probably assert in debug mode, but they
! 1356: are to cleanup in case any locks remained open */
! 1357: if (pFile->local.nReaders){
! 1358: pFile->shared->nReaders --;
! 1359: }
! 1360: if (pFile->local.bReserved){
! 1361: pFile->shared->bReserved = FALSE;
! 1362: }
! 1363: if (pFile->local.bPending){
! 1364: pFile->shared->bPending = FALSE;
! 1365: }
! 1366: if (pFile->local.bExclusive){
! 1367: pFile->shared->bExclusive = FALSE;
! 1368: }
! 1369:
! 1370: /* De-reference and close our copy of the shared memory handle */
! 1371: osUnmapViewOfFile(pFile->shared);
! 1372: osCloseHandle(pFile->hShared);
! 1373:
! 1374: /* Done with the mutex */
! 1375: winceMutexRelease(pFile->hMutex);
! 1376: osCloseHandle(pFile->hMutex);
! 1377: pFile->hMutex = NULL;
! 1378: }
! 1379: }
! 1380:
! 1381: /*
! 1382: ** An implementation of the LockFile() API of Windows for CE
! 1383: */
! 1384: static BOOL winceLockFile(
! 1385: HANDLE *phFile,
! 1386: DWORD dwFileOffsetLow,
! 1387: DWORD dwFileOffsetHigh,
! 1388: DWORD nNumberOfBytesToLockLow,
! 1389: DWORD nNumberOfBytesToLockHigh
! 1390: ){
! 1391: winFile *pFile = HANDLE_TO_WINFILE(phFile);
! 1392: BOOL bReturn = FALSE;
! 1393:
! 1394: UNUSED_PARAMETER(dwFileOffsetHigh);
! 1395: UNUSED_PARAMETER(nNumberOfBytesToLockHigh);
! 1396:
! 1397: if (!pFile->hMutex) return TRUE;
! 1398: winceMutexAcquire(pFile->hMutex);
! 1399:
! 1400: /* Wanting an exclusive lock? */
! 1401: if (dwFileOffsetLow == (DWORD)SHARED_FIRST
! 1402: && nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){
! 1403: if (pFile->shared->nReaders == 0 && pFile->shared->bExclusive == 0){
! 1404: pFile->shared->bExclusive = TRUE;
! 1405: pFile->local.bExclusive = TRUE;
! 1406: bReturn = TRUE;
! 1407: }
! 1408: }
! 1409:
! 1410: /* Want a read-only lock? */
! 1411: else if (dwFileOffsetLow == (DWORD)SHARED_FIRST &&
! 1412: nNumberOfBytesToLockLow == 1){
! 1413: if (pFile->shared->bExclusive == 0){
! 1414: pFile->local.nReaders ++;
! 1415: if (pFile->local.nReaders == 1){
! 1416: pFile->shared->nReaders ++;
! 1417: }
! 1418: bReturn = TRUE;
! 1419: }
! 1420: }
! 1421:
! 1422: /* Want a pending lock? */
! 1423: else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToLockLow == 1){
! 1424: /* If no pending lock has been acquired, then acquire it */
! 1425: if (pFile->shared->bPending == 0) {
! 1426: pFile->shared->bPending = TRUE;
! 1427: pFile->local.bPending = TRUE;
! 1428: bReturn = TRUE;
! 1429: }
! 1430: }
! 1431:
! 1432: /* Want a reserved lock? */
! 1433: else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToLockLow == 1){
! 1434: if (pFile->shared->bReserved == 0) {
! 1435: pFile->shared->bReserved = TRUE;
! 1436: pFile->local.bReserved = TRUE;
! 1437: bReturn = TRUE;
! 1438: }
! 1439: }
! 1440:
! 1441: winceMutexRelease(pFile->hMutex);
! 1442: return bReturn;
! 1443: }
! 1444:
! 1445: /*
! 1446: ** An implementation of the UnlockFile API of Windows for CE
! 1447: */
! 1448: static BOOL winceUnlockFile(
! 1449: HANDLE *phFile,
! 1450: DWORD dwFileOffsetLow,
! 1451: DWORD dwFileOffsetHigh,
! 1452: DWORD nNumberOfBytesToUnlockLow,
! 1453: DWORD nNumberOfBytesToUnlockHigh
! 1454: ){
! 1455: winFile *pFile = HANDLE_TO_WINFILE(phFile);
! 1456: BOOL bReturn = FALSE;
! 1457:
! 1458: UNUSED_PARAMETER(dwFileOffsetHigh);
! 1459: UNUSED_PARAMETER(nNumberOfBytesToUnlockHigh);
! 1460:
! 1461: if (!pFile->hMutex) return TRUE;
! 1462: winceMutexAcquire(pFile->hMutex);
! 1463:
! 1464: /* Releasing a reader lock or an exclusive lock */
! 1465: if (dwFileOffsetLow == (DWORD)SHARED_FIRST){
! 1466: /* Did we have an exclusive lock? */
! 1467: if (pFile->local.bExclusive){
! 1468: assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE);
! 1469: pFile->local.bExclusive = FALSE;
! 1470: pFile->shared->bExclusive = FALSE;
! 1471: bReturn = TRUE;
! 1472: }
! 1473:
! 1474: /* Did we just have a reader lock? */
! 1475: else if (pFile->local.nReaders){
! 1476: assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE || nNumberOfBytesToUnlockLow == 1);
! 1477: pFile->local.nReaders --;
! 1478: if (pFile->local.nReaders == 0)
! 1479: {
! 1480: pFile->shared->nReaders --;
! 1481: }
! 1482: bReturn = TRUE;
! 1483: }
! 1484: }
! 1485:
! 1486: /* Releasing a pending lock */
! 1487: else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToUnlockLow == 1){
! 1488: if (pFile->local.bPending){
! 1489: pFile->local.bPending = FALSE;
! 1490: pFile->shared->bPending = FALSE;
! 1491: bReturn = TRUE;
! 1492: }
! 1493: }
! 1494: /* Releasing a reserved lock */
! 1495: else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1){
! 1496: if (pFile->local.bReserved) {
! 1497: pFile->local.bReserved = FALSE;
! 1498: pFile->shared->bReserved = FALSE;
! 1499: bReturn = TRUE;
! 1500: }
! 1501: }
! 1502:
! 1503: winceMutexRelease(pFile->hMutex);
! 1504: return bReturn;
! 1505: }
! 1506:
! 1507: /*
! 1508: ** An implementation of the LockFileEx() API of Windows for CE
! 1509: */
! 1510: static BOOL winceLockFileEx(
! 1511: HANDLE *phFile,
! 1512: DWORD dwFlags,
! 1513: DWORD dwReserved,
! 1514: DWORD nNumberOfBytesToLockLow,
! 1515: DWORD nNumberOfBytesToLockHigh,
! 1516: LPOVERLAPPED lpOverlapped
! 1517: ){
! 1518: UNUSED_PARAMETER(dwReserved);
! 1519: UNUSED_PARAMETER(nNumberOfBytesToLockHigh);
! 1520:
! 1521: /* If the caller wants a shared read lock, forward this call
! 1522: ** to winceLockFile */
! 1523: if (lpOverlapped->Offset == (DWORD)SHARED_FIRST &&
! 1524: dwFlags == 1 &&
! 1525: nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){
! 1526: return winceLockFile(phFile, SHARED_FIRST, 0, 1, 0);
! 1527: }
! 1528: return FALSE;
! 1529: }
! 1530: /*
! 1531: ** End of the special code for wince
! 1532: *****************************************************************************/
! 1533: #endif /* SQLITE_OS_WINCE */
! 1534:
! 1535: /*****************************************************************************
! 1536: ** The next group of routines implement the I/O methods specified
! 1537: ** by the sqlite3_io_methods object.
! 1538: ******************************************************************************/
! 1539:
! 1540: /*
! 1541: ** Some Microsoft compilers lack this definition.
! 1542: */
! 1543: #ifndef INVALID_SET_FILE_POINTER
! 1544: # define INVALID_SET_FILE_POINTER ((DWORD)-1)
! 1545: #endif
! 1546:
! 1547: /*
! 1548: ** Move the current position of the file handle passed as the first
! 1549: ** argument to offset iOffset within the file. If successful, return 0.
! 1550: ** Otherwise, set pFile->lastErrno and return non-zero.
! 1551: */
! 1552: static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
! 1553: LONG upperBits; /* Most sig. 32 bits of new offset */
! 1554: LONG lowerBits; /* Least sig. 32 bits of new offset */
! 1555: DWORD dwRet; /* Value returned by SetFilePointer() */
! 1556: DWORD lastErrno; /* Value returned by GetLastError() */
! 1557:
! 1558: upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
! 1559: lowerBits = (LONG)(iOffset & 0xffffffff);
! 1560:
! 1561: /* API oddity: If successful, SetFilePointer() returns a dword
! 1562: ** containing the lower 32-bits of the new file-offset. Or, if it fails,
! 1563: ** it returns INVALID_SET_FILE_POINTER. However according to MSDN,
! 1564: ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine
! 1565: ** whether an error has actually occured, it is also necessary to call
! 1566: ** GetLastError().
! 1567: */
! 1568: dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
! 1569:
! 1570: if( (dwRet==INVALID_SET_FILE_POINTER
! 1571: && ((lastErrno = osGetLastError())!=NO_ERROR)) ){
! 1572: pFile->lastErrno = lastErrno;
! 1573: winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
! 1574: "seekWinFile", pFile->zPath);
! 1575: return 1;
! 1576: }
! 1577:
! 1578: return 0;
! 1579: }
! 1580:
! 1581: /*
! 1582: ** Close a file.
! 1583: **
! 1584: ** It is reported that an attempt to close a handle might sometimes
! 1585: ** fail. This is a very unreasonable result, but Windows is notorious
! 1586: ** for being unreasonable so I do not doubt that it might happen. If
! 1587: ** the close fails, we pause for 100 milliseconds and try again. As
! 1588: ** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before
! 1589: ** giving up and returning an error.
! 1590: */
! 1591: #define MX_CLOSE_ATTEMPT 3
! 1592: static int winClose(sqlite3_file *id){
! 1593: int rc, cnt = 0;
! 1594: winFile *pFile = (winFile*)id;
! 1595:
! 1596: assert( id!=0 );
! 1597: assert( pFile->pShm==0 );
! 1598: OSTRACE(("CLOSE %d\n", pFile->h));
! 1599: do{
! 1600: rc = osCloseHandle(pFile->h);
! 1601: /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */
! 1602: }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (osSleep(100), 1) );
! 1603: #if SQLITE_OS_WINCE
! 1604: #define WINCE_DELETION_ATTEMPTS 3
! 1605: winceDestroyLock(pFile);
! 1606: if( pFile->zDeleteOnClose ){
! 1607: int cnt = 0;
! 1608: while(
! 1609: osDeleteFileW(pFile->zDeleteOnClose)==0
! 1610: && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff
! 1611: && cnt++ < WINCE_DELETION_ATTEMPTS
! 1612: ){
! 1613: osSleep(100); /* Wait a little before trying again */
! 1614: }
! 1615: sqlite3_free(pFile->zDeleteOnClose);
! 1616: }
! 1617: #endif
! 1618: OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed"));
! 1619: OpenCounter(-1);
! 1620: return rc ? SQLITE_OK
! 1621: : winLogError(SQLITE_IOERR_CLOSE, osGetLastError(),
! 1622: "winClose", pFile->zPath);
! 1623: }
! 1624:
! 1625: /*
! 1626: ** Read data from a file into a buffer. Return SQLITE_OK if all
! 1627: ** bytes were read successfully and SQLITE_IOERR if anything goes
! 1628: ** wrong.
! 1629: */
! 1630: static int winRead(
! 1631: sqlite3_file *id, /* File to read from */
! 1632: void *pBuf, /* Write content into this buffer */
! 1633: int amt, /* Number of bytes to read */
! 1634: sqlite3_int64 offset /* Begin reading at this offset */
! 1635: ){
! 1636: winFile *pFile = (winFile*)id; /* file handle */
! 1637: DWORD nRead; /* Number of bytes actually read from file */
! 1638: int nRetry = 0; /* Number of retrys */
! 1639:
! 1640: assert( id!=0 );
! 1641: SimulateIOError(return SQLITE_IOERR_READ);
! 1642: OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype));
! 1643:
! 1644: if( seekWinFile(pFile, offset) ){
! 1645: return SQLITE_FULL;
! 1646: }
! 1647: while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
! 1648: DWORD lastErrno;
! 1649: if( retryIoerr(&nRetry, &lastErrno) ) continue;
! 1650: pFile->lastErrno = lastErrno;
! 1651: return winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
! 1652: "winRead", pFile->zPath);
! 1653: }
! 1654: logIoerr(nRetry);
! 1655: if( nRead<(DWORD)amt ){
! 1656: /* Unread parts of the buffer must be zero-filled */
! 1657: memset(&((char*)pBuf)[nRead], 0, amt-nRead);
! 1658: return SQLITE_IOERR_SHORT_READ;
! 1659: }
! 1660:
! 1661: return SQLITE_OK;
! 1662: }
! 1663:
! 1664: /*
! 1665: ** Write data from a buffer into a file. Return SQLITE_OK on success
! 1666: ** or some other error code on failure.
! 1667: */
! 1668: static int winWrite(
! 1669: sqlite3_file *id, /* File to write into */
! 1670: const void *pBuf, /* The bytes to be written */
! 1671: int amt, /* Number of bytes to write */
! 1672: sqlite3_int64 offset /* Offset into the file to begin writing at */
! 1673: ){
! 1674: int rc; /* True if error has occured, else false */
! 1675: winFile *pFile = (winFile*)id; /* File handle */
! 1676: int nRetry = 0; /* Number of retries */
! 1677:
! 1678: assert( amt>0 );
! 1679: assert( pFile );
! 1680: SimulateIOError(return SQLITE_IOERR_WRITE);
! 1681: SimulateDiskfullError(return SQLITE_FULL);
! 1682:
! 1683: OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype));
! 1684:
! 1685: rc = seekWinFile(pFile, offset);
! 1686: if( rc==0 ){
! 1687: u8 *aRem = (u8 *)pBuf; /* Data yet to be written */
! 1688: int nRem = amt; /* Number of bytes yet to be written */
! 1689: DWORD nWrite; /* Bytes written by each WriteFile() call */
! 1690: DWORD lastErrno = NO_ERROR; /* Value returned by GetLastError() */
! 1691:
! 1692: while( nRem>0 ){
! 1693: if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
! 1694: if( retryIoerr(&nRetry, &lastErrno) ) continue;
! 1695: break;
! 1696: }
! 1697: if( nWrite<=0 ) break;
! 1698: aRem += nWrite;
! 1699: nRem -= nWrite;
! 1700: }
! 1701: if( nRem>0 ){
! 1702: pFile->lastErrno = lastErrno;
! 1703: rc = 1;
! 1704: }
! 1705: }
! 1706:
! 1707: if( rc ){
! 1708: if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL )
! 1709: || ( pFile->lastErrno==ERROR_DISK_FULL )){
! 1710: return SQLITE_FULL;
! 1711: }
! 1712: return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno,
! 1713: "winWrite", pFile->zPath);
! 1714: }else{
! 1715: logIoerr(nRetry);
! 1716: }
! 1717: return SQLITE_OK;
! 1718: }
! 1719:
! 1720: /*
! 1721: ** Truncate an open file to a specified size
! 1722: */
! 1723: static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
! 1724: winFile *pFile = (winFile*)id; /* File handle object */
! 1725: int rc = SQLITE_OK; /* Return code for this function */
! 1726:
! 1727: assert( pFile );
! 1728:
! 1729: OSTRACE(("TRUNCATE %d %lld\n", pFile->h, nByte));
! 1730: SimulateIOError(return SQLITE_IOERR_TRUNCATE);
! 1731:
! 1732: /* If the user has configured a chunk-size for this file, truncate the
! 1733: ** file so that it consists of an integer number of chunks (i.e. the
! 1734: ** actual file size after the operation may be larger than the requested
! 1735: ** size).
! 1736: */
! 1737: if( pFile->szChunk>0 ){
! 1738: nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
! 1739: }
! 1740:
! 1741: /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
! 1742: if( seekWinFile(pFile, nByte) ){
! 1743: rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
! 1744: "winTruncate1", pFile->zPath);
! 1745: }else if( 0==osSetEndOfFile(pFile->h) ){
! 1746: pFile->lastErrno = osGetLastError();
! 1747: rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
! 1748: "winTruncate2", pFile->zPath);
! 1749: }
! 1750:
! 1751: OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok"));
! 1752: return rc;
! 1753: }
! 1754:
! 1755: #ifdef SQLITE_TEST
! 1756: /*
! 1757: ** Count the number of fullsyncs and normal syncs. This is used to test
! 1758: ** that syncs and fullsyncs are occuring at the right times.
! 1759: */
! 1760: int sqlite3_sync_count = 0;
! 1761: int sqlite3_fullsync_count = 0;
! 1762: #endif
! 1763:
! 1764: /*
! 1765: ** Make sure all writes to a particular file are committed to disk.
! 1766: */
! 1767: static int winSync(sqlite3_file *id, int flags){
! 1768: #ifndef SQLITE_NO_SYNC
! 1769: /*
! 1770: ** Used only when SQLITE_NO_SYNC is not defined.
! 1771: */
! 1772: BOOL rc;
! 1773: #endif
! 1774: #if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || \
! 1775: (defined(SQLITE_TEST) && defined(SQLITE_DEBUG))
! 1776: /*
! 1777: ** Used when SQLITE_NO_SYNC is not defined and by the assert() and/or
! 1778: ** OSTRACE() macros.
! 1779: */
! 1780: winFile *pFile = (winFile*)id;
! 1781: #else
! 1782: UNUSED_PARAMETER(id);
! 1783: #endif
! 1784:
! 1785: assert( pFile );
! 1786: /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */
! 1787: assert((flags&0x0F)==SQLITE_SYNC_NORMAL
! 1788: || (flags&0x0F)==SQLITE_SYNC_FULL
! 1789: );
! 1790:
! 1791: OSTRACE(("SYNC %d lock=%d\n", pFile->h, pFile->locktype));
! 1792:
! 1793: /* Unix cannot, but some systems may return SQLITE_FULL from here. This
! 1794: ** line is to test that doing so does not cause any problems.
! 1795: */
! 1796: SimulateDiskfullError( return SQLITE_FULL );
! 1797:
! 1798: #ifndef SQLITE_TEST
! 1799: UNUSED_PARAMETER(flags);
! 1800: #else
! 1801: if( (flags&0x0F)==SQLITE_SYNC_FULL ){
! 1802: sqlite3_fullsync_count++;
! 1803: }
! 1804: sqlite3_sync_count++;
! 1805: #endif
! 1806:
! 1807: /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
! 1808: ** no-op
! 1809: */
! 1810: #ifdef SQLITE_NO_SYNC
! 1811: return SQLITE_OK;
! 1812: #else
! 1813: rc = osFlushFileBuffers(pFile->h);
! 1814: SimulateIOError( rc=FALSE );
! 1815: if( rc ){
! 1816: return SQLITE_OK;
! 1817: }else{
! 1818: pFile->lastErrno = osGetLastError();
! 1819: return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno,
! 1820: "winSync", pFile->zPath);
! 1821: }
! 1822: #endif
! 1823: }
! 1824:
! 1825: /*
! 1826: ** Determine the current size of a file in bytes
! 1827: */
! 1828: static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
! 1829: DWORD upperBits;
! 1830: DWORD lowerBits;
! 1831: winFile *pFile = (winFile*)id;
! 1832: DWORD lastErrno;
! 1833:
! 1834: assert( id!=0 );
! 1835: SimulateIOError(return SQLITE_IOERR_FSTAT);
! 1836: lowerBits = osGetFileSize(pFile->h, &upperBits);
! 1837: if( (lowerBits == INVALID_FILE_SIZE)
! 1838: && ((lastErrno = osGetLastError())!=NO_ERROR) )
! 1839: {
! 1840: pFile->lastErrno = lastErrno;
! 1841: return winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno,
! 1842: "winFileSize", pFile->zPath);
! 1843: }
! 1844: *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits;
! 1845: return SQLITE_OK;
! 1846: }
! 1847:
! 1848: /*
! 1849: ** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems.
! 1850: */
! 1851: #ifndef LOCKFILE_FAIL_IMMEDIATELY
! 1852: # define LOCKFILE_FAIL_IMMEDIATELY 1
! 1853: #endif
! 1854:
! 1855: /*
! 1856: ** Acquire a reader lock.
! 1857: ** Different API routines are called depending on whether or not this
! 1858: ** is Win9x or WinNT.
! 1859: */
! 1860: static int getReadLock(winFile *pFile){
! 1861: int res;
! 1862: if( isNT() ){
! 1863: OVERLAPPED ovlp;
! 1864: ovlp.Offset = SHARED_FIRST;
! 1865: ovlp.OffsetHigh = 0;
! 1866: ovlp.hEvent = 0;
! 1867: res = osLockFileEx(pFile->h, LOCKFILE_FAIL_IMMEDIATELY,
! 1868: 0, SHARED_SIZE, 0, &ovlp);
! 1869: /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
! 1870: */
! 1871: #if SQLITE_OS_WINCE==0
! 1872: }else{
! 1873: int lk;
! 1874: sqlite3_randomness(sizeof(lk), &lk);
! 1875: pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1));
! 1876: res = osLockFile(pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
! 1877: #endif
! 1878: }
! 1879: if( res == 0 ){
! 1880: pFile->lastErrno = osGetLastError();
! 1881: /* No need to log a failure to lock */
! 1882: }
! 1883: return res;
! 1884: }
! 1885:
! 1886: /*
! 1887: ** Undo a readlock
! 1888: */
! 1889: static int unlockReadLock(winFile *pFile){
! 1890: int res;
! 1891: DWORD lastErrno;
! 1892: if( isNT() ){
! 1893: res = osUnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
! 1894: /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
! 1895: */
! 1896: #if SQLITE_OS_WINCE==0
! 1897: }else{
! 1898: res = osUnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0);
! 1899: #endif
! 1900: }
! 1901: if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){
! 1902: pFile->lastErrno = lastErrno;
! 1903: winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno,
! 1904: "unlockReadLock", pFile->zPath);
! 1905: }
! 1906: return res;
! 1907: }
! 1908:
! 1909: /*
! 1910: ** Lock the file with the lock specified by parameter locktype - one
! 1911: ** of the following:
! 1912: **
! 1913: ** (1) SHARED_LOCK
! 1914: ** (2) RESERVED_LOCK
! 1915: ** (3) PENDING_LOCK
! 1916: ** (4) EXCLUSIVE_LOCK
! 1917: **
! 1918: ** Sometimes when requesting one lock state, additional lock states
! 1919: ** are inserted in between. The locking might fail on one of the later
! 1920: ** transitions leaving the lock state different from what it started but
! 1921: ** still short of its goal. The following chart shows the allowed
! 1922: ** transitions and the inserted intermediate states:
! 1923: **
! 1924: ** UNLOCKED -> SHARED
! 1925: ** SHARED -> RESERVED
! 1926: ** SHARED -> (PENDING) -> EXCLUSIVE
! 1927: ** RESERVED -> (PENDING) -> EXCLUSIVE
! 1928: ** PENDING -> EXCLUSIVE
! 1929: **
! 1930: ** This routine will only increase a lock. The winUnlock() routine
! 1931: ** erases all locks at once and returns us immediately to locking level 0.
! 1932: ** It is not possible to lower the locking level one step at a time. You
! 1933: ** must go straight to locking level 0.
! 1934: */
! 1935: static int winLock(sqlite3_file *id, int locktype){
! 1936: int rc = SQLITE_OK; /* Return code from subroutines */
! 1937: int res = 1; /* Result of a Windows lock call */
! 1938: int newLocktype; /* Set pFile->locktype to this value before exiting */
! 1939: int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
! 1940: winFile *pFile = (winFile*)id;
! 1941: DWORD lastErrno = NO_ERROR;
! 1942:
! 1943: assert( id!=0 );
! 1944: OSTRACE(("LOCK %d %d was %d(%d)\n",
! 1945: pFile->h, locktype, pFile->locktype, pFile->sharedLockByte));
! 1946:
! 1947: /* If there is already a lock of this type or more restrictive on the
! 1948: ** OsFile, do nothing. Don't use the end_lock: exit path, as
! 1949: ** sqlite3OsEnterMutex() hasn't been called yet.
! 1950: */
! 1951: if( pFile->locktype>=locktype ){
! 1952: return SQLITE_OK;
! 1953: }
! 1954:
! 1955: /* Make sure the locking sequence is correct
! 1956: */
! 1957: assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
! 1958: assert( locktype!=PENDING_LOCK );
! 1959: assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
! 1960:
! 1961: /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
! 1962: ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of
! 1963: ** the PENDING_LOCK byte is temporary.
! 1964: */
! 1965: newLocktype = pFile->locktype;
! 1966: if( (pFile->locktype==NO_LOCK)
! 1967: || ( (locktype==EXCLUSIVE_LOCK)
! 1968: && (pFile->locktype==RESERVED_LOCK))
! 1969: ){
! 1970: int cnt = 3;
! 1971: while( cnt-->0 && (res = osLockFile(pFile->h, PENDING_BYTE, 0, 1, 0))==0 ){
! 1972: /* Try 3 times to get the pending lock. This is needed to work
! 1973: ** around problems caused by indexing and/or anti-virus software on
! 1974: ** Windows systems.
! 1975: ** If you are using this code as a model for alternative VFSes, do not
! 1976: ** copy this retry logic. It is a hack intended for Windows only.
! 1977: */
! 1978: OSTRACE(("could not get a PENDING lock. cnt=%d\n", cnt));
! 1979: if( cnt ) osSleep(1);
! 1980: }
! 1981: gotPendingLock = res;
! 1982: if( !res ){
! 1983: lastErrno = osGetLastError();
! 1984: }
! 1985: }
! 1986:
! 1987: /* Acquire a shared lock
! 1988: */
! 1989: if( locktype==SHARED_LOCK && res ){
! 1990: assert( pFile->locktype==NO_LOCK );
! 1991: res = getReadLock(pFile);
! 1992: if( res ){
! 1993: newLocktype = SHARED_LOCK;
! 1994: }else{
! 1995: lastErrno = osGetLastError();
! 1996: }
! 1997: }
! 1998:
! 1999: /* Acquire a RESERVED lock
! 2000: */
! 2001: if( locktype==RESERVED_LOCK && res ){
! 2002: assert( pFile->locktype==SHARED_LOCK );
! 2003: res = osLockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
! 2004: if( res ){
! 2005: newLocktype = RESERVED_LOCK;
! 2006: }else{
! 2007: lastErrno = osGetLastError();
! 2008: }
! 2009: }
! 2010:
! 2011: /* Acquire a PENDING lock
! 2012: */
! 2013: if( locktype==EXCLUSIVE_LOCK && res ){
! 2014: newLocktype = PENDING_LOCK;
! 2015: gotPendingLock = 0;
! 2016: }
! 2017:
! 2018: /* Acquire an EXCLUSIVE lock
! 2019: */
! 2020: if( locktype==EXCLUSIVE_LOCK && res ){
! 2021: assert( pFile->locktype>=SHARED_LOCK );
! 2022: res = unlockReadLock(pFile);
! 2023: OSTRACE(("unreadlock = %d\n", res));
! 2024: res = osLockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
! 2025: if( res ){
! 2026: newLocktype = EXCLUSIVE_LOCK;
! 2027: }else{
! 2028: lastErrno = osGetLastError();
! 2029: OSTRACE(("error-code = %d\n", lastErrno));
! 2030: getReadLock(pFile);
! 2031: }
! 2032: }
! 2033:
! 2034: /* If we are holding a PENDING lock that ought to be released, then
! 2035: ** release it now.
! 2036: */
! 2037: if( gotPendingLock && locktype==SHARED_LOCK ){
! 2038: osUnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
! 2039: }
! 2040:
! 2041: /* Update the state of the lock has held in the file descriptor then
! 2042: ** return the appropriate result code.
! 2043: */
! 2044: if( res ){
! 2045: rc = SQLITE_OK;
! 2046: }else{
! 2047: OSTRACE(("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
! 2048: locktype, newLocktype));
! 2049: pFile->lastErrno = lastErrno;
! 2050: rc = SQLITE_BUSY;
! 2051: }
! 2052: pFile->locktype = (u8)newLocktype;
! 2053: return rc;
! 2054: }
! 2055:
! 2056: /*
! 2057: ** This routine checks if there is a RESERVED lock held on the specified
! 2058: ** file by this or any other process. If such a lock is held, return
! 2059: ** non-zero, otherwise zero.
! 2060: */
! 2061: static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
! 2062: int rc;
! 2063: winFile *pFile = (winFile*)id;
! 2064:
! 2065: SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
! 2066:
! 2067: assert( id!=0 );
! 2068: if( pFile->locktype>=RESERVED_LOCK ){
! 2069: rc = 1;
! 2070: OSTRACE(("TEST WR-LOCK %d %d (local)\n", pFile->h, rc));
! 2071: }else{
! 2072: rc = osLockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
! 2073: if( rc ){
! 2074: osUnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
! 2075: }
! 2076: rc = !rc;
! 2077: OSTRACE(("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc));
! 2078: }
! 2079: *pResOut = rc;
! 2080: return SQLITE_OK;
! 2081: }
! 2082:
! 2083: /*
! 2084: ** Lower the locking level on file descriptor id to locktype. locktype
! 2085: ** must be either NO_LOCK or SHARED_LOCK.
! 2086: **
! 2087: ** If the locking level of the file descriptor is already at or below
! 2088: ** the requested locking level, this routine is a no-op.
! 2089: **
! 2090: ** It is not possible for this routine to fail if the second argument
! 2091: ** is NO_LOCK. If the second argument is SHARED_LOCK then this routine
! 2092: ** might return SQLITE_IOERR;
! 2093: */
! 2094: static int winUnlock(sqlite3_file *id, int locktype){
! 2095: int type;
! 2096: winFile *pFile = (winFile*)id;
! 2097: int rc = SQLITE_OK;
! 2098: assert( pFile!=0 );
! 2099: assert( locktype<=SHARED_LOCK );
! 2100: OSTRACE(("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
! 2101: pFile->locktype, pFile->sharedLockByte));
! 2102: type = pFile->locktype;
! 2103: if( type>=EXCLUSIVE_LOCK ){
! 2104: osUnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
! 2105: if( locktype==SHARED_LOCK && !getReadLock(pFile) ){
! 2106: /* This should never happen. We should always be able to
! 2107: ** reacquire the read lock */
! 2108: rc = winLogError(SQLITE_IOERR_UNLOCK, osGetLastError(),
! 2109: "winUnlock", pFile->zPath);
! 2110: }
! 2111: }
! 2112: if( type>=RESERVED_LOCK ){
! 2113: osUnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
! 2114: }
! 2115: if( locktype==NO_LOCK && type>=SHARED_LOCK ){
! 2116: unlockReadLock(pFile);
! 2117: }
! 2118: if( type>=PENDING_LOCK ){
! 2119: osUnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
! 2120: }
! 2121: pFile->locktype = (u8)locktype;
! 2122: return rc;
! 2123: }
! 2124:
! 2125: /*
! 2126: ** If *pArg is inititially negative then this is a query. Set *pArg to
! 2127: ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
! 2128: **
! 2129: ** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
! 2130: */
! 2131: static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){
! 2132: if( *pArg<0 ){
! 2133: *pArg = (pFile->ctrlFlags & mask)!=0;
! 2134: }else if( (*pArg)==0 ){
! 2135: pFile->ctrlFlags &= ~mask;
! 2136: }else{
! 2137: pFile->ctrlFlags |= mask;
! 2138: }
! 2139: }
! 2140:
! 2141: /*
! 2142: ** Control and query of the open file handle.
! 2143: */
! 2144: static int winFileControl(sqlite3_file *id, int op, void *pArg){
! 2145: winFile *pFile = (winFile*)id;
! 2146: switch( op ){
! 2147: case SQLITE_FCNTL_LOCKSTATE: {
! 2148: *(int*)pArg = pFile->locktype;
! 2149: return SQLITE_OK;
! 2150: }
! 2151: case SQLITE_LAST_ERRNO: {
! 2152: *(int*)pArg = (int)pFile->lastErrno;
! 2153: return SQLITE_OK;
! 2154: }
! 2155: case SQLITE_FCNTL_CHUNK_SIZE: {
! 2156: pFile->szChunk = *(int *)pArg;
! 2157: return SQLITE_OK;
! 2158: }
! 2159: case SQLITE_FCNTL_SIZE_HINT: {
! 2160: if( pFile->szChunk>0 ){
! 2161: sqlite3_int64 oldSz;
! 2162: int rc = winFileSize(id, &oldSz);
! 2163: if( rc==SQLITE_OK ){
! 2164: sqlite3_int64 newSz = *(sqlite3_int64*)pArg;
! 2165: if( newSz>oldSz ){
! 2166: SimulateIOErrorBenign(1);
! 2167: rc = winTruncate(id, newSz);
! 2168: SimulateIOErrorBenign(0);
! 2169: }
! 2170: }
! 2171: return rc;
! 2172: }
! 2173: return SQLITE_OK;
! 2174: }
! 2175: case SQLITE_FCNTL_PERSIST_WAL: {
! 2176: winModeBit(pFile, WINFILE_PERSIST_WAL, (int*)pArg);
! 2177: return SQLITE_OK;
! 2178: }
! 2179: case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
! 2180: winModeBit(pFile, WINFILE_PSOW, (int*)pArg);
! 2181: return SQLITE_OK;
! 2182: }
! 2183: case SQLITE_FCNTL_VFSNAME: {
! 2184: *(char**)pArg = sqlite3_mprintf("win32");
! 2185: return SQLITE_OK;
! 2186: }
! 2187: case SQLITE_FCNTL_WIN32_AV_RETRY: {
! 2188: int *a = (int*)pArg;
! 2189: if( a[0]>0 ){
! 2190: win32IoerrRetry = a[0];
! 2191: }else{
! 2192: a[0] = win32IoerrRetry;
! 2193: }
! 2194: if( a[1]>0 ){
! 2195: win32IoerrRetryDelay = a[1];
! 2196: }else{
! 2197: a[1] = win32IoerrRetryDelay;
! 2198: }
! 2199: return SQLITE_OK;
! 2200: }
! 2201: }
! 2202: return SQLITE_NOTFOUND;
! 2203: }
! 2204:
! 2205: /*
! 2206: ** Return the sector size in bytes of the underlying block device for
! 2207: ** the specified file. This is almost always 512 bytes, but may be
! 2208: ** larger for some devices.
! 2209: **
! 2210: ** SQLite code assumes this function cannot fail. It also assumes that
! 2211: ** if two files are created in the same file-system directory (i.e.
! 2212: ** a database and its journal file) that the sector size will be the
! 2213: ** same for both.
! 2214: */
! 2215: static int winSectorSize(sqlite3_file *id){
! 2216: (void)id;
! 2217: return SQLITE_DEFAULT_SECTOR_SIZE;
! 2218: }
! 2219:
! 2220: /*
! 2221: ** Return a vector of device characteristics.
! 2222: */
! 2223: static int winDeviceCharacteristics(sqlite3_file *id){
! 2224: winFile *p = (winFile*)id;
! 2225: return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN |
! 2226: ((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
! 2227: }
! 2228:
! 2229: #ifndef SQLITE_OMIT_WAL
! 2230:
! 2231: /*
! 2232: ** Windows will only let you create file view mappings
! 2233: ** on allocation size granularity boundaries.
! 2234: ** During sqlite3_os_init() we do a GetSystemInfo()
! 2235: ** to get the granularity size.
! 2236: */
! 2237: SYSTEM_INFO winSysInfo;
! 2238:
! 2239: /*
! 2240: ** Helper functions to obtain and relinquish the global mutex. The
! 2241: ** global mutex is used to protect the winLockInfo objects used by
! 2242: ** this file, all of which may be shared by multiple threads.
! 2243: **
! 2244: ** Function winShmMutexHeld() is used to assert() that the global mutex
! 2245: ** is held when required. This function is only used as part of assert()
! 2246: ** statements. e.g.
! 2247: **
! 2248: ** winShmEnterMutex()
! 2249: ** assert( winShmMutexHeld() );
! 2250: ** winShmLeaveMutex()
! 2251: */
! 2252: static void winShmEnterMutex(void){
! 2253: sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
! 2254: }
! 2255: static void winShmLeaveMutex(void){
! 2256: sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
! 2257: }
! 2258: #ifdef SQLITE_DEBUG
! 2259: static int winShmMutexHeld(void) {
! 2260: return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
! 2261: }
! 2262: #endif
! 2263:
! 2264: /*
! 2265: ** Object used to represent a single file opened and mmapped to provide
! 2266: ** shared memory. When multiple threads all reference the same
! 2267: ** log-summary, each thread has its own winFile object, but they all
! 2268: ** point to a single instance of this object. In other words, each
! 2269: ** log-summary is opened only once per process.
! 2270: **
! 2271: ** winShmMutexHeld() must be true when creating or destroying
! 2272: ** this object or while reading or writing the following fields:
! 2273: **
! 2274: ** nRef
! 2275: ** pNext
! 2276: **
! 2277: ** The following fields are read-only after the object is created:
! 2278: **
! 2279: ** fid
! 2280: ** zFilename
! 2281: **
! 2282: ** Either winShmNode.mutex must be held or winShmNode.nRef==0 and
! 2283: ** winShmMutexHeld() is true when reading or writing any other field
! 2284: ** in this structure.
! 2285: **
! 2286: */
! 2287: struct winShmNode {
! 2288: sqlite3_mutex *mutex; /* Mutex to access this object */
! 2289: char *zFilename; /* Name of the file */
! 2290: winFile hFile; /* File handle from winOpen */
! 2291:
! 2292: int szRegion; /* Size of shared-memory regions */
! 2293: int nRegion; /* Size of array apRegion */
! 2294: struct ShmRegion {
! 2295: HANDLE hMap; /* File handle from CreateFileMapping */
! 2296: void *pMap;
! 2297: } *aRegion;
! 2298: DWORD lastErrno; /* The Windows errno from the last I/O error */
! 2299:
! 2300: int nRef; /* Number of winShm objects pointing to this */
! 2301: winShm *pFirst; /* All winShm objects pointing to this */
! 2302: winShmNode *pNext; /* Next in list of all winShmNode objects */
! 2303: #ifdef SQLITE_DEBUG
! 2304: u8 nextShmId; /* Next available winShm.id value */
! 2305: #endif
! 2306: };
! 2307:
! 2308: /*
! 2309: ** A global array of all winShmNode objects.
! 2310: **
! 2311: ** The winShmMutexHeld() must be true while reading or writing this list.
! 2312: */
! 2313: static winShmNode *winShmNodeList = 0;
! 2314:
! 2315: /*
! 2316: ** Structure used internally by this VFS to record the state of an
! 2317: ** open shared memory connection.
! 2318: **
! 2319: ** The following fields are initialized when this object is created and
! 2320: ** are read-only thereafter:
! 2321: **
! 2322: ** winShm.pShmNode
! 2323: ** winShm.id
! 2324: **
! 2325: ** All other fields are read/write. The winShm.pShmNode->mutex must be held
! 2326: ** while accessing any read/write fields.
! 2327: */
! 2328: struct winShm {
! 2329: winShmNode *pShmNode; /* The underlying winShmNode object */
! 2330: winShm *pNext; /* Next winShm with the same winShmNode */
! 2331: u8 hasMutex; /* True if holding the winShmNode mutex */
! 2332: u16 sharedMask; /* Mask of shared locks held */
! 2333: u16 exclMask; /* Mask of exclusive locks held */
! 2334: #ifdef SQLITE_DEBUG
! 2335: u8 id; /* Id of this connection with its winShmNode */
! 2336: #endif
! 2337: };
! 2338:
! 2339: /*
! 2340: ** Constants used for locking
! 2341: */
! 2342: #define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
! 2343: #define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
! 2344:
! 2345: /*
! 2346: ** Apply advisory locks for all n bytes beginning at ofst.
! 2347: */
! 2348: #define _SHM_UNLCK 1
! 2349: #define _SHM_RDLCK 2
! 2350: #define _SHM_WRLCK 3
! 2351: static int winShmSystemLock(
! 2352: winShmNode *pFile, /* Apply locks to this open shared-memory segment */
! 2353: int lockType, /* _SHM_UNLCK, _SHM_RDLCK, or _SHM_WRLCK */
! 2354: int ofst, /* Offset to first byte to be locked/unlocked */
! 2355: int nByte /* Number of bytes to lock or unlock */
! 2356: ){
! 2357: OVERLAPPED ovlp;
! 2358: DWORD dwFlags;
! 2359: int rc = 0; /* Result code form Lock/UnlockFileEx() */
! 2360:
! 2361: /* Access to the winShmNode object is serialized by the caller */
! 2362: assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
! 2363:
! 2364: /* Initialize the locking parameters */
! 2365: dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
! 2366: if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
! 2367:
! 2368: memset(&ovlp, 0, sizeof(OVERLAPPED));
! 2369: ovlp.Offset = ofst;
! 2370:
! 2371: /* Release/Acquire the system-level lock */
! 2372: if( lockType==_SHM_UNLCK ){
! 2373: rc = osUnlockFileEx(pFile->hFile.h, 0, nByte, 0, &ovlp);
! 2374: }else{
! 2375: rc = osLockFileEx(pFile->hFile.h, dwFlags, 0, nByte, 0, &ovlp);
! 2376: }
! 2377:
! 2378: if( rc!= 0 ){
! 2379: rc = SQLITE_OK;
! 2380: }else{
! 2381: pFile->lastErrno = osGetLastError();
! 2382: rc = SQLITE_BUSY;
! 2383: }
! 2384:
! 2385: OSTRACE(("SHM-LOCK %d %s %s 0x%08lx\n",
! 2386: pFile->hFile.h,
! 2387: rc==SQLITE_OK ? "ok" : "failed",
! 2388: lockType==_SHM_UNLCK ? "UnlockFileEx" : "LockFileEx",
! 2389: pFile->lastErrno));
! 2390:
! 2391: return rc;
! 2392: }
! 2393:
! 2394: /* Forward references to VFS methods */
! 2395: static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*);
! 2396: static int winDelete(sqlite3_vfs *,const char*,int);
! 2397:
! 2398: /*
! 2399: ** Purge the winShmNodeList list of all entries with winShmNode.nRef==0.
! 2400: **
! 2401: ** This is not a VFS shared-memory method; it is a utility function called
! 2402: ** by VFS shared-memory methods.
! 2403: */
! 2404: static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
! 2405: winShmNode **pp;
! 2406: winShmNode *p;
! 2407: BOOL bRc;
! 2408: assert( winShmMutexHeld() );
! 2409: pp = &winShmNodeList;
! 2410: while( (p = *pp)!=0 ){
! 2411: if( p->nRef==0 ){
! 2412: int i;
! 2413: if( p->mutex ) sqlite3_mutex_free(p->mutex);
! 2414: for(i=0; i<p->nRegion; i++){
! 2415: bRc = osUnmapViewOfFile(p->aRegion[i].pMap);
! 2416: OSTRACE(("SHM-PURGE pid-%d unmap region=%d %s\n",
! 2417: (int)osGetCurrentProcessId(), i,
! 2418: bRc ? "ok" : "failed"));
! 2419: bRc = osCloseHandle(p->aRegion[i].hMap);
! 2420: OSTRACE(("SHM-PURGE pid-%d close region=%d %s\n",
! 2421: (int)osGetCurrentProcessId(), i,
! 2422: bRc ? "ok" : "failed"));
! 2423: }
! 2424: if( p->hFile.h != INVALID_HANDLE_VALUE ){
! 2425: SimulateIOErrorBenign(1);
! 2426: winClose((sqlite3_file *)&p->hFile);
! 2427: SimulateIOErrorBenign(0);
! 2428: }
! 2429: if( deleteFlag ){
! 2430: SimulateIOErrorBenign(1);
! 2431: sqlite3BeginBenignMalloc();
! 2432: winDelete(pVfs, p->zFilename, 0);
! 2433: sqlite3EndBenignMalloc();
! 2434: SimulateIOErrorBenign(0);
! 2435: }
! 2436: *pp = p->pNext;
! 2437: sqlite3_free(p->aRegion);
! 2438: sqlite3_free(p);
! 2439: }else{
! 2440: pp = &p->pNext;
! 2441: }
! 2442: }
! 2443: }
! 2444:
! 2445: /*
! 2446: ** Open the shared-memory area associated with database file pDbFd.
! 2447: **
! 2448: ** When opening a new shared-memory file, if no other instances of that
! 2449: ** file are currently open, in this process or in other processes, then
! 2450: ** the file must be truncated to zero length or have its header cleared.
! 2451: */
! 2452: static int winOpenSharedMemory(winFile *pDbFd){
! 2453: struct winShm *p; /* The connection to be opened */
! 2454: struct winShmNode *pShmNode = 0; /* The underlying mmapped file */
! 2455: int rc; /* Result code */
! 2456: struct winShmNode *pNew; /* Newly allocated winShmNode */
! 2457: int nName; /* Size of zName in bytes */
! 2458:
! 2459: assert( pDbFd->pShm==0 ); /* Not previously opened */
! 2460:
! 2461: /* Allocate space for the new sqlite3_shm object. Also speculatively
! 2462: ** allocate space for a new winShmNode and filename.
! 2463: */
! 2464: p = sqlite3_malloc( sizeof(*p) );
! 2465: if( p==0 ) return SQLITE_IOERR_NOMEM;
! 2466: memset(p, 0, sizeof(*p));
! 2467: nName = sqlite3Strlen30(pDbFd->zPath);
! 2468: pNew = sqlite3_malloc( sizeof(*pShmNode) + nName + 17 );
! 2469: if( pNew==0 ){
! 2470: sqlite3_free(p);
! 2471: return SQLITE_IOERR_NOMEM;
! 2472: }
! 2473: memset(pNew, 0, sizeof(*pNew) + nName + 17);
! 2474: pNew->zFilename = (char*)&pNew[1];
! 2475: sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
! 2476: sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename);
! 2477:
! 2478: /* Look to see if there is an existing winShmNode that can be used.
! 2479: ** If no matching winShmNode currently exists, create a new one.
! 2480: */
! 2481: winShmEnterMutex();
! 2482: for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){
! 2483: /* TBD need to come up with better match here. Perhaps
! 2484: ** use FILE_ID_BOTH_DIR_INFO Structure.
! 2485: */
! 2486: if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break;
! 2487: }
! 2488: if( pShmNode ){
! 2489: sqlite3_free(pNew);
! 2490: }else{
! 2491: pShmNode = pNew;
! 2492: pNew = 0;
! 2493: ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE;
! 2494: pShmNode->pNext = winShmNodeList;
! 2495: winShmNodeList = pShmNode;
! 2496:
! 2497: pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
! 2498: if( pShmNode->mutex==0 ){
! 2499: rc = SQLITE_IOERR_NOMEM;
! 2500: goto shm_open_err;
! 2501: }
! 2502:
! 2503: rc = winOpen(pDbFd->pVfs,
! 2504: pShmNode->zFilename, /* Name of the file (UTF-8) */
! 2505: (sqlite3_file*)&pShmNode->hFile, /* File handle here */
! 2506: SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, /* Mode flags */
! 2507: 0);
! 2508: if( SQLITE_OK!=rc ){
! 2509: goto shm_open_err;
! 2510: }
! 2511:
! 2512: /* Check to see if another process is holding the dead-man switch.
! 2513: ** If not, truncate the file to zero length.
! 2514: */
! 2515: if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
! 2516: rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
! 2517: if( rc!=SQLITE_OK ){
! 2518: rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
! 2519: "winOpenShm", pDbFd->zPath);
! 2520: }
! 2521: }
! 2522: if( rc==SQLITE_OK ){
! 2523: winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
! 2524: rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1);
! 2525: }
! 2526: if( rc ) goto shm_open_err;
! 2527: }
! 2528:
! 2529: /* Make the new connection a child of the winShmNode */
! 2530: p->pShmNode = pShmNode;
! 2531: #ifdef SQLITE_DEBUG
! 2532: p->id = pShmNode->nextShmId++;
! 2533: #endif
! 2534: pShmNode->nRef++;
! 2535: pDbFd->pShm = p;
! 2536: winShmLeaveMutex();
! 2537:
! 2538: /* The reference count on pShmNode has already been incremented under
! 2539: ** the cover of the winShmEnterMutex() mutex and the pointer from the
! 2540: ** new (struct winShm) object to the pShmNode has been set. All that is
! 2541: ** left to do is to link the new object into the linked list starting
! 2542: ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex
! 2543: ** mutex.
! 2544: */
! 2545: sqlite3_mutex_enter(pShmNode->mutex);
! 2546: p->pNext = pShmNode->pFirst;
! 2547: pShmNode->pFirst = p;
! 2548: sqlite3_mutex_leave(pShmNode->mutex);
! 2549: return SQLITE_OK;
! 2550:
! 2551: /* Jump here on any error */
! 2552: shm_open_err:
! 2553: winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
! 2554: winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */
! 2555: sqlite3_free(p);
! 2556: sqlite3_free(pNew);
! 2557: winShmLeaveMutex();
! 2558: return rc;
! 2559: }
! 2560:
! 2561: /*
! 2562: ** Close a connection to shared-memory. Delete the underlying
! 2563: ** storage if deleteFlag is true.
! 2564: */
! 2565: static int winShmUnmap(
! 2566: sqlite3_file *fd, /* Database holding shared memory */
! 2567: int deleteFlag /* Delete after closing if true */
! 2568: ){
! 2569: winFile *pDbFd; /* Database holding shared-memory */
! 2570: winShm *p; /* The connection to be closed */
! 2571: winShmNode *pShmNode; /* The underlying shared-memory file */
! 2572: winShm **pp; /* For looping over sibling connections */
! 2573:
! 2574: pDbFd = (winFile*)fd;
! 2575: p = pDbFd->pShm;
! 2576: if( p==0 ) return SQLITE_OK;
! 2577: pShmNode = p->pShmNode;
! 2578:
! 2579: /* Remove connection p from the set of connections associated
! 2580: ** with pShmNode */
! 2581: sqlite3_mutex_enter(pShmNode->mutex);
! 2582: for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
! 2583: *pp = p->pNext;
! 2584:
! 2585: /* Free the connection p */
! 2586: sqlite3_free(p);
! 2587: pDbFd->pShm = 0;
! 2588: sqlite3_mutex_leave(pShmNode->mutex);
! 2589:
! 2590: /* If pShmNode->nRef has reached 0, then close the underlying
! 2591: ** shared-memory file, too */
! 2592: winShmEnterMutex();
! 2593: assert( pShmNode->nRef>0 );
! 2594: pShmNode->nRef--;
! 2595: if( pShmNode->nRef==0 ){
! 2596: winShmPurge(pDbFd->pVfs, deleteFlag);
! 2597: }
! 2598: winShmLeaveMutex();
! 2599:
! 2600: return SQLITE_OK;
! 2601: }
! 2602:
! 2603: /*
! 2604: ** Change the lock state for a shared-memory segment.
! 2605: */
! 2606: static int winShmLock(
! 2607: sqlite3_file *fd, /* Database file holding the shared memory */
! 2608: int ofst, /* First lock to acquire or release */
! 2609: int n, /* Number of locks to acquire or release */
! 2610: int flags /* What to do with the lock */
! 2611: ){
! 2612: winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */
! 2613: winShm *p = pDbFd->pShm; /* The shared memory being locked */
! 2614: winShm *pX; /* For looping over all siblings */
! 2615: winShmNode *pShmNode = p->pShmNode;
! 2616: int rc = SQLITE_OK; /* Result code */
! 2617: u16 mask; /* Mask of locks to take or release */
! 2618:
! 2619: assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
! 2620: assert( n>=1 );
! 2621: assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
! 2622: || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
! 2623: || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
! 2624: || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
! 2625: assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
! 2626:
! 2627: mask = (u16)((1U<<(ofst+n)) - (1U<<ofst));
! 2628: assert( n>1 || mask==(1<<ofst) );
! 2629: sqlite3_mutex_enter(pShmNode->mutex);
! 2630: if( flags & SQLITE_SHM_UNLOCK ){
! 2631: u16 allMask = 0; /* Mask of locks held by siblings */
! 2632:
! 2633: /* See if any siblings hold this same lock */
! 2634: for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
! 2635: if( pX==p ) continue;
! 2636: assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
! 2637: allMask |= pX->sharedMask;
! 2638: }
! 2639:
! 2640: /* Unlock the system-level locks */
! 2641: if( (mask & allMask)==0 ){
! 2642: rc = winShmSystemLock(pShmNode, _SHM_UNLCK, ofst+WIN_SHM_BASE, n);
! 2643: }else{
! 2644: rc = SQLITE_OK;
! 2645: }
! 2646:
! 2647: /* Undo the local locks */
! 2648: if( rc==SQLITE_OK ){
! 2649: p->exclMask &= ~mask;
! 2650: p->sharedMask &= ~mask;
! 2651: }
! 2652: }else if( flags & SQLITE_SHM_SHARED ){
! 2653: u16 allShared = 0; /* Union of locks held by connections other than "p" */
! 2654:
! 2655: /* Find out which shared locks are already held by sibling connections.
! 2656: ** If any sibling already holds an exclusive lock, go ahead and return
! 2657: ** SQLITE_BUSY.
! 2658: */
! 2659: for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
! 2660: if( (pX->exclMask & mask)!=0 ){
! 2661: rc = SQLITE_BUSY;
! 2662: break;
! 2663: }
! 2664: allShared |= pX->sharedMask;
! 2665: }
! 2666:
! 2667: /* Get shared locks at the system level, if necessary */
! 2668: if( rc==SQLITE_OK ){
! 2669: if( (allShared & mask)==0 ){
! 2670: rc = winShmSystemLock(pShmNode, _SHM_RDLCK, ofst+WIN_SHM_BASE, n);
! 2671: }else{
! 2672: rc = SQLITE_OK;
! 2673: }
! 2674: }
! 2675:
! 2676: /* Get the local shared locks */
! 2677: if( rc==SQLITE_OK ){
! 2678: p->sharedMask |= mask;
! 2679: }
! 2680: }else{
! 2681: /* Make sure no sibling connections hold locks that will block this
! 2682: ** lock. If any do, return SQLITE_BUSY right away.
! 2683: */
! 2684: for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
! 2685: if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
! 2686: rc = SQLITE_BUSY;
! 2687: break;
! 2688: }
! 2689: }
! 2690:
! 2691: /* Get the exclusive locks at the system level. Then if successful
! 2692: ** also mark the local connection as being locked.
! 2693: */
! 2694: if( rc==SQLITE_OK ){
! 2695: rc = winShmSystemLock(pShmNode, _SHM_WRLCK, ofst+WIN_SHM_BASE, n);
! 2696: if( rc==SQLITE_OK ){
! 2697: assert( (p->sharedMask & mask)==0 );
! 2698: p->exclMask |= mask;
! 2699: }
! 2700: }
! 2701: }
! 2702: sqlite3_mutex_leave(pShmNode->mutex);
! 2703: OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x %s\n",
! 2704: p->id, (int)osGetCurrentProcessId(), p->sharedMask, p->exclMask,
! 2705: rc ? "failed" : "ok"));
! 2706: return rc;
! 2707: }
! 2708:
! 2709: /*
! 2710: ** Implement a memory barrier or memory fence on shared memory.
! 2711: **
! 2712: ** All loads and stores begun before the barrier must complete before
! 2713: ** any load or store begun after the barrier.
! 2714: */
! 2715: static void winShmBarrier(
! 2716: sqlite3_file *fd /* Database holding the shared memory */
! 2717: ){
! 2718: UNUSED_PARAMETER(fd);
! 2719: /* MemoryBarrier(); // does not work -- do not know why not */
! 2720: winShmEnterMutex();
! 2721: winShmLeaveMutex();
! 2722: }
! 2723:
! 2724: /*
! 2725: ** This function is called to obtain a pointer to region iRegion of the
! 2726: ** shared-memory associated with the database file fd. Shared-memory regions
! 2727: ** are numbered starting from zero. Each shared-memory region is szRegion
! 2728: ** bytes in size.
! 2729: **
! 2730: ** If an error occurs, an error code is returned and *pp is set to NULL.
! 2731: **
! 2732: ** Otherwise, if the isWrite parameter is 0 and the requested shared-memory
! 2733: ** region has not been allocated (by any client, including one running in a
! 2734: ** separate process), then *pp is set to NULL and SQLITE_OK returned. If
! 2735: ** isWrite is non-zero and the requested shared-memory region has not yet
! 2736: ** been allocated, it is allocated by this function.
! 2737: **
! 2738: ** If the shared-memory region has already been allocated or is allocated by
! 2739: ** this call as described above, then it is mapped into this processes
! 2740: ** address space (if it is not already), *pp is set to point to the mapped
! 2741: ** memory and SQLITE_OK returned.
! 2742: */
! 2743: static int winShmMap(
! 2744: sqlite3_file *fd, /* Handle open on database file */
! 2745: int iRegion, /* Region to retrieve */
! 2746: int szRegion, /* Size of regions */
! 2747: int isWrite, /* True to extend file if necessary */
! 2748: void volatile **pp /* OUT: Mapped memory */
! 2749: ){
! 2750: winFile *pDbFd = (winFile*)fd;
! 2751: winShm *p = pDbFd->pShm;
! 2752: winShmNode *pShmNode;
! 2753: int rc = SQLITE_OK;
! 2754:
! 2755: if( !p ){
! 2756: rc = winOpenSharedMemory(pDbFd);
! 2757: if( rc!=SQLITE_OK ) return rc;
! 2758: p = pDbFd->pShm;
! 2759: }
! 2760: pShmNode = p->pShmNode;
! 2761:
! 2762: sqlite3_mutex_enter(pShmNode->mutex);
! 2763: assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
! 2764:
! 2765: if( pShmNode->nRegion<=iRegion ){
! 2766: struct ShmRegion *apNew; /* New aRegion[] array */
! 2767: int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
! 2768: sqlite3_int64 sz; /* Current size of wal-index file */
! 2769:
! 2770: pShmNode->szRegion = szRegion;
! 2771:
! 2772: /* The requested region is not mapped into this processes address space.
! 2773: ** Check to see if it has been allocated (i.e. if the wal-index file is
! 2774: ** large enough to contain the requested region).
! 2775: */
! 2776: rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz);
! 2777: if( rc!=SQLITE_OK ){
! 2778: rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(),
! 2779: "winShmMap1", pDbFd->zPath);
! 2780: goto shmpage_out;
! 2781: }
! 2782:
! 2783: if( sz<nByte ){
! 2784: /* The requested memory region does not exist. If isWrite is set to
! 2785: ** zero, exit early. *pp will be set to NULL and SQLITE_OK returned.
! 2786: **
! 2787: ** Alternatively, if isWrite is non-zero, use ftruncate() to allocate
! 2788: ** the requested memory region.
! 2789: */
! 2790: if( !isWrite ) goto shmpage_out;
! 2791: rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte);
! 2792: if( rc!=SQLITE_OK ){
! 2793: rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(),
! 2794: "winShmMap2", pDbFd->zPath);
! 2795: goto shmpage_out;
! 2796: }
! 2797: }
! 2798:
! 2799: /* Map the requested memory region into this processes address space. */
! 2800: apNew = (struct ShmRegion *)sqlite3_realloc(
! 2801: pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
! 2802: );
! 2803: if( !apNew ){
! 2804: rc = SQLITE_IOERR_NOMEM;
! 2805: goto shmpage_out;
! 2806: }
! 2807: pShmNode->aRegion = apNew;
! 2808:
! 2809: while( pShmNode->nRegion<=iRegion ){
! 2810: HANDLE hMap; /* file-mapping handle */
! 2811: void *pMap = 0; /* Mapped memory region */
! 2812:
! 2813: hMap = osCreateFileMapping(pShmNode->hFile.h,
! 2814: NULL, PAGE_READWRITE, 0, nByte, NULL
! 2815: );
! 2816: OSTRACE(("SHM-MAP pid-%d create region=%d nbyte=%d %s\n",
! 2817: (int)osGetCurrentProcessId(), pShmNode->nRegion, nByte,
! 2818: hMap ? "ok" : "failed"));
! 2819: if( hMap ){
! 2820: int iOffset = pShmNode->nRegion*szRegion;
! 2821: int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
! 2822: pMap = osMapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
! 2823: 0, iOffset - iOffsetShift, szRegion + iOffsetShift
! 2824: );
! 2825: OSTRACE(("SHM-MAP pid-%d map region=%d offset=%d size=%d %s\n",
! 2826: (int)osGetCurrentProcessId(), pShmNode->nRegion, iOffset,
! 2827: szRegion, pMap ? "ok" : "failed"));
! 2828: }
! 2829: if( !pMap ){
! 2830: pShmNode->lastErrno = osGetLastError();
! 2831: rc = winLogError(SQLITE_IOERR_SHMMAP, pShmNode->lastErrno,
! 2832: "winShmMap3", pDbFd->zPath);
! 2833: if( hMap ) osCloseHandle(hMap);
! 2834: goto shmpage_out;
! 2835: }
! 2836:
! 2837: pShmNode->aRegion[pShmNode->nRegion].pMap = pMap;
! 2838: pShmNode->aRegion[pShmNode->nRegion].hMap = hMap;
! 2839: pShmNode->nRegion++;
! 2840: }
! 2841: }
! 2842:
! 2843: shmpage_out:
! 2844: if( pShmNode->nRegion>iRegion ){
! 2845: int iOffset = iRegion*szRegion;
! 2846: int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
! 2847: char *p = (char *)pShmNode->aRegion[iRegion].pMap;
! 2848: *pp = (void *)&p[iOffsetShift];
! 2849: }else{
! 2850: *pp = 0;
! 2851: }
! 2852: sqlite3_mutex_leave(pShmNode->mutex);
! 2853: return rc;
! 2854: }
! 2855:
! 2856: #else
! 2857: # define winShmMap 0
! 2858: # define winShmLock 0
! 2859: # define winShmBarrier 0
! 2860: # define winShmUnmap 0
! 2861: #endif /* #ifndef SQLITE_OMIT_WAL */
! 2862:
! 2863: /*
! 2864: ** Here ends the implementation of all sqlite3_file methods.
! 2865: **
! 2866: ********************** End sqlite3_file Methods *******************************
! 2867: ******************************************************************************/
! 2868:
! 2869: /*
! 2870: ** This vector defines all the methods that can operate on an
! 2871: ** sqlite3_file for win32.
! 2872: */
! 2873: static const sqlite3_io_methods winIoMethod = {
! 2874: 2, /* iVersion */
! 2875: winClose, /* xClose */
! 2876: winRead, /* xRead */
! 2877: winWrite, /* xWrite */
! 2878: winTruncate, /* xTruncate */
! 2879: winSync, /* xSync */
! 2880: winFileSize, /* xFileSize */
! 2881: winLock, /* xLock */
! 2882: winUnlock, /* xUnlock */
! 2883: winCheckReservedLock, /* xCheckReservedLock */
! 2884: winFileControl, /* xFileControl */
! 2885: winSectorSize, /* xSectorSize */
! 2886: winDeviceCharacteristics, /* xDeviceCharacteristics */
! 2887: winShmMap, /* xShmMap */
! 2888: winShmLock, /* xShmLock */
! 2889: winShmBarrier, /* xShmBarrier */
! 2890: winShmUnmap /* xShmUnmap */
! 2891: };
! 2892:
! 2893: /****************************************************************************
! 2894: **************************** sqlite3_vfs methods ****************************
! 2895: **
! 2896: ** This division contains the implementation of methods on the
! 2897: ** sqlite3_vfs object.
! 2898: */
! 2899:
! 2900: /*
! 2901: ** Convert a UTF-8 filename into whatever form the underlying
! 2902: ** operating system wants filenames in. Space to hold the result
! 2903: ** is obtained from malloc and must be freed by the calling
! 2904: ** function.
! 2905: */
! 2906: static void *convertUtf8Filename(const char *zFilename){
! 2907: void *zConverted = 0;
! 2908: if( isNT() ){
! 2909: zConverted = utf8ToUnicode(zFilename);
! 2910: /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
! 2911: */
! 2912: #if SQLITE_OS_WINCE==0
! 2913: }else{
! 2914: zConverted = sqlite3_win32_utf8_to_mbcs(zFilename);
! 2915: #endif
! 2916: }
! 2917: /* caller will handle out of memory */
! 2918: return zConverted;
! 2919: }
! 2920:
! 2921: /*
! 2922: ** Create a temporary file name in zBuf. zBuf must be big enough to
! 2923: ** hold at pVfs->mxPathname characters.
! 2924: */
! 2925: static int getTempname(int nBuf, char *zBuf){
! 2926: static char zChars[] =
! 2927: "abcdefghijklmnopqrstuvwxyz"
! 2928: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
! 2929: "0123456789";
! 2930: size_t i, j;
! 2931: char zTempPath[MAX_PATH+2];
! 2932:
! 2933: /* It's odd to simulate an io-error here, but really this is just
! 2934: ** using the io-error infrastructure to test that SQLite handles this
! 2935: ** function failing.
! 2936: */
! 2937: SimulateIOError( return SQLITE_IOERR );
! 2938:
! 2939: if( sqlite3_temp_directory ){
! 2940: sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory);
! 2941: }else if( isNT() ){
! 2942: char *zMulti;
! 2943: WCHAR zWidePath[MAX_PATH];
! 2944: osGetTempPathW(MAX_PATH-30, zWidePath);
! 2945: zMulti = unicodeToUtf8(zWidePath);
! 2946: if( zMulti ){
! 2947: sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti);
! 2948: sqlite3_free(zMulti);
! 2949: }else{
! 2950: return SQLITE_IOERR_NOMEM;
! 2951: }
! 2952: /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
! 2953: ** Since the ANSI version of these Windows API do not exist for WINCE,
! 2954: ** it's important to not reference them for WINCE builds.
! 2955: */
! 2956: #if SQLITE_OS_WINCE==0
! 2957: }else{
! 2958: char *zUtf8;
! 2959: char zMbcsPath[MAX_PATH];
! 2960: osGetTempPathA(MAX_PATH-30, zMbcsPath);
! 2961: zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath);
! 2962: if( zUtf8 ){
! 2963: sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8);
! 2964: sqlite3_free(zUtf8);
! 2965: }else{
! 2966: return SQLITE_IOERR_NOMEM;
! 2967: }
! 2968: #endif
! 2969: }
! 2970:
! 2971: /* Check that the output buffer is large enough for the temporary file
! 2972: ** name. If it is not, return SQLITE_ERROR.
! 2973: */
! 2974: if( (sqlite3Strlen30(zTempPath) + sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX) + 18) >= nBuf ){
! 2975: return SQLITE_ERROR;
! 2976: }
! 2977:
! 2978: for(i=sqlite3Strlen30(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
! 2979: zTempPath[i] = 0;
! 2980:
! 2981: sqlite3_snprintf(nBuf-18, zBuf,
! 2982: "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath);
! 2983: j = sqlite3Strlen30(zBuf);
! 2984: sqlite3_randomness(15, &zBuf[j]);
! 2985: for(i=0; i<15; i++, j++){
! 2986: zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
! 2987: }
! 2988: zBuf[j] = 0;
! 2989: zBuf[j+1] = 0;
! 2990:
! 2991: OSTRACE(("TEMP FILENAME: %s\n", zBuf));
! 2992: return SQLITE_OK;
! 2993: }
! 2994:
! 2995: /*
! 2996: ** Open a file.
! 2997: */
! 2998: static int winOpen(
! 2999: sqlite3_vfs *pVfs, /* Not used */
! 3000: const char *zName, /* Name of the file (UTF-8) */
! 3001: sqlite3_file *id, /* Write the SQLite file handle here */
! 3002: int flags, /* Open mode flags */
! 3003: int *pOutFlags /* Status return flags */
! 3004: ){
! 3005: HANDLE h;
! 3006: DWORD lastErrno;
! 3007: DWORD dwDesiredAccess;
! 3008: DWORD dwShareMode;
! 3009: DWORD dwCreationDisposition;
! 3010: DWORD dwFlagsAndAttributes = 0;
! 3011: #if SQLITE_OS_WINCE
! 3012: int isTemp = 0;
! 3013: #endif
! 3014: winFile *pFile = (winFile*)id;
! 3015: void *zConverted; /* Filename in OS encoding */
! 3016: const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */
! 3017: int cnt = 0;
! 3018:
! 3019: /* If argument zPath is a NULL pointer, this function is required to open
! 3020: ** a temporary file. Use this buffer to store the file name in.
! 3021: */
! 3022: char zTmpname[MAX_PATH+2]; /* Buffer used to create temp filename */
! 3023:
! 3024: int rc = SQLITE_OK; /* Function Return Code */
! 3025: #if !defined(NDEBUG) || SQLITE_OS_WINCE
! 3026: int eType = flags&0xFFFFFF00; /* Type of file to open */
! 3027: #endif
! 3028:
! 3029: int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
! 3030: int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
! 3031: int isCreate = (flags & SQLITE_OPEN_CREATE);
! 3032: #ifndef NDEBUG
! 3033: int isReadonly = (flags & SQLITE_OPEN_READONLY);
! 3034: #endif
! 3035: int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
! 3036:
! 3037: #ifndef NDEBUG
! 3038: int isOpenJournal = (isCreate && (
! 3039: eType==SQLITE_OPEN_MASTER_JOURNAL
! 3040: || eType==SQLITE_OPEN_MAIN_JOURNAL
! 3041: || eType==SQLITE_OPEN_WAL
! 3042: ));
! 3043: #endif
! 3044:
! 3045: /* Check the following statements are true:
! 3046: **
! 3047: ** (a) Exactly one of the READWRITE and READONLY flags must be set, and
! 3048: ** (b) if CREATE is set, then READWRITE must also be set, and
! 3049: ** (c) if EXCLUSIVE is set, then CREATE must also be set.
! 3050: ** (d) if DELETEONCLOSE is set, then CREATE must also be set.
! 3051: */
! 3052: assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
! 3053: assert(isCreate==0 || isReadWrite);
! 3054: assert(isExclusive==0 || isCreate);
! 3055: assert(isDelete==0 || isCreate);
! 3056:
! 3057: /* The main DB, main journal, WAL file and master journal are never
! 3058: ** automatically deleted. Nor are they ever temporary files. */
! 3059: assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
! 3060: assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
! 3061: assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
! 3062: assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
! 3063:
! 3064: /* Assert that the upper layer has set one of the "file-type" flags. */
! 3065: assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
! 3066: || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
! 3067: || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
! 3068: || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
! 3069: );
! 3070:
! 3071: assert( id!=0 );
! 3072: UNUSED_PARAMETER(pVfs);
! 3073:
! 3074: pFile->h = INVALID_HANDLE_VALUE;
! 3075:
! 3076: /* If the second argument to this function is NULL, generate a
! 3077: ** temporary file name to use
! 3078: */
! 3079: if( !zUtf8Name ){
! 3080: assert(isDelete && !isOpenJournal);
! 3081: rc = getTempname(MAX_PATH+2, zTmpname);
! 3082: if( rc!=SQLITE_OK ){
! 3083: return rc;
! 3084: }
! 3085: zUtf8Name = zTmpname;
! 3086: }
! 3087:
! 3088: /* Database filenames are double-zero terminated if they are not
! 3089: ** URIs with parameters. Hence, they can always be passed into
! 3090: ** sqlite3_uri_parameter().
! 3091: */
! 3092: assert( (eType!=SQLITE_OPEN_MAIN_DB) || (flags & SQLITE_OPEN_URI) ||
! 3093: zUtf8Name[strlen(zUtf8Name)+1]==0 );
! 3094:
! 3095: /* Convert the filename to the system encoding. */
! 3096: zConverted = convertUtf8Filename(zUtf8Name);
! 3097: if( zConverted==0 ){
! 3098: return SQLITE_IOERR_NOMEM;
! 3099: }
! 3100:
! 3101: if( isReadWrite ){
! 3102: dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
! 3103: }else{
! 3104: dwDesiredAccess = GENERIC_READ;
! 3105: }
! 3106:
! 3107: /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is
! 3108: ** created. SQLite doesn't use it to indicate "exclusive access"
! 3109: ** as it is usually understood.
! 3110: */
! 3111: if( isExclusive ){
! 3112: /* Creates a new file, only if it does not already exist. */
! 3113: /* If the file exists, it fails. */
! 3114: dwCreationDisposition = CREATE_NEW;
! 3115: }else if( isCreate ){
! 3116: /* Open existing file, or create if it doesn't exist */
! 3117: dwCreationDisposition = OPEN_ALWAYS;
! 3118: }else{
! 3119: /* Opens a file, only if it exists. */
! 3120: dwCreationDisposition = OPEN_EXISTING;
! 3121: }
! 3122:
! 3123: dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
! 3124:
! 3125: if( isDelete ){
! 3126: #if SQLITE_OS_WINCE
! 3127: dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN;
! 3128: isTemp = 1;
! 3129: #else
! 3130: dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY
! 3131: | FILE_ATTRIBUTE_HIDDEN
! 3132: | FILE_FLAG_DELETE_ON_CLOSE;
! 3133: #endif
! 3134: }else{
! 3135: dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
! 3136: }
! 3137: /* Reports from the internet are that performance is always
! 3138: ** better if FILE_FLAG_RANDOM_ACCESS is used. Ticket #2699. */
! 3139: #if SQLITE_OS_WINCE
! 3140: dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
! 3141: #endif
! 3142:
! 3143: if( isNT() ){
! 3144: while( (h = osCreateFileW((LPCWSTR)zConverted,
! 3145: dwDesiredAccess,
! 3146: dwShareMode, NULL,
! 3147: dwCreationDisposition,
! 3148: dwFlagsAndAttributes,
! 3149: NULL))==INVALID_HANDLE_VALUE &&
! 3150: retryIoerr(&cnt, &lastErrno) ){}
! 3151: /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
! 3152: ** Since the ANSI version of these Windows API do not exist for WINCE,
! 3153: ** it's important to not reference them for WINCE builds.
! 3154: */
! 3155: #if SQLITE_OS_WINCE==0
! 3156: }else{
! 3157: while( (h = osCreateFileA((LPCSTR)zConverted,
! 3158: dwDesiredAccess,
! 3159: dwShareMode, NULL,
! 3160: dwCreationDisposition,
! 3161: dwFlagsAndAttributes,
! 3162: NULL))==INVALID_HANDLE_VALUE &&
! 3163: retryIoerr(&cnt, &lastErrno) ){}
! 3164: #endif
! 3165: }
! 3166:
! 3167: logIoerr(cnt);
! 3168:
! 3169: OSTRACE(("OPEN %d %s 0x%lx %s\n",
! 3170: h, zName, dwDesiredAccess,
! 3171: h==INVALID_HANDLE_VALUE ? "failed" : "ok"));
! 3172:
! 3173: if( h==INVALID_HANDLE_VALUE ){
! 3174: pFile->lastErrno = lastErrno;
! 3175: winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
! 3176: sqlite3_free(zConverted);
! 3177: if( isReadWrite && !isExclusive ){
! 3178: return winOpen(pVfs, zName, id,
! 3179: ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags);
! 3180: }else{
! 3181: return SQLITE_CANTOPEN_BKPT;
! 3182: }
! 3183: }
! 3184:
! 3185: if( pOutFlags ){
! 3186: if( isReadWrite ){
! 3187: *pOutFlags = SQLITE_OPEN_READWRITE;
! 3188: }else{
! 3189: *pOutFlags = SQLITE_OPEN_READONLY;
! 3190: }
! 3191: }
! 3192:
! 3193: memset(pFile, 0, sizeof(*pFile));
! 3194: pFile->pMethod = &winIoMethod;
! 3195: pFile->h = h;
! 3196: pFile->lastErrno = NO_ERROR;
! 3197: pFile->pVfs = pVfs;
! 3198: pFile->pShm = 0;
! 3199: pFile->zPath = zName;
! 3200: if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
! 3201: pFile->ctrlFlags |= WINFILE_PSOW;
! 3202: }
! 3203:
! 3204: #if SQLITE_OS_WINCE
! 3205: if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
! 3206: && !winceCreateLock(zName, pFile)
! 3207: ){
! 3208: osCloseHandle(h);
! 3209: sqlite3_free(zConverted);
! 3210: return SQLITE_CANTOPEN_BKPT;
! 3211: }
! 3212: if( isTemp ){
! 3213: pFile->zDeleteOnClose = zConverted;
! 3214: }else
! 3215: #endif
! 3216: {
! 3217: sqlite3_free(zConverted);
! 3218: }
! 3219:
! 3220: OpenCounter(+1);
! 3221: return rc;
! 3222: }
! 3223:
! 3224: /*
! 3225: ** Delete the named file.
! 3226: **
! 3227: ** Note that Windows does not allow a file to be deleted if some other
! 3228: ** process has it open. Sometimes a virus scanner or indexing program
! 3229: ** will open a journal file shortly after it is created in order to do
! 3230: ** whatever it does. While this other process is holding the
! 3231: ** file open, we will be unable to delete it. To work around this
! 3232: ** problem, we delay 100 milliseconds and try to delete again. Up
! 3233: ** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
! 3234: ** up and returning an error.
! 3235: */
! 3236: static int winDelete(
! 3237: sqlite3_vfs *pVfs, /* Not used on win32 */
! 3238: const char *zFilename, /* Name of file to delete */
! 3239: int syncDir /* Not used on win32 */
! 3240: ){
! 3241: int cnt = 0;
! 3242: int rc;
! 3243: DWORD lastErrno;
! 3244: void *zConverted;
! 3245: UNUSED_PARAMETER(pVfs);
! 3246: UNUSED_PARAMETER(syncDir);
! 3247:
! 3248: SimulateIOError(return SQLITE_IOERR_DELETE);
! 3249: zConverted = convertUtf8Filename(zFilename);
! 3250: if( zConverted==0 ){
! 3251: return SQLITE_IOERR_NOMEM;
! 3252: }
! 3253: if( isNT() ){
! 3254: rc = 1;
! 3255: while( osGetFileAttributesW(zConverted)!=INVALID_FILE_ATTRIBUTES &&
! 3256: (rc = osDeleteFileW(zConverted))==0 && retryIoerr(&cnt, &lastErrno) ){}
! 3257: rc = rc ? SQLITE_OK : SQLITE_ERROR;
! 3258: /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
! 3259: ** Since the ANSI version of these Windows API do not exist for WINCE,
! 3260: ** it's important to not reference them for WINCE builds.
! 3261: */
! 3262: #if SQLITE_OS_WINCE==0
! 3263: }else{
! 3264: rc = 1;
! 3265: while( osGetFileAttributesA(zConverted)!=INVALID_FILE_ATTRIBUTES &&
! 3266: (rc = osDeleteFileA(zConverted))==0 && retryIoerr(&cnt, &lastErrno) ){}
! 3267: rc = rc ? SQLITE_OK : SQLITE_ERROR;
! 3268: #endif
! 3269: }
! 3270: if( rc ){
! 3271: rc = winLogError(SQLITE_IOERR_DELETE, lastErrno,
! 3272: "winDelete", zFilename);
! 3273: }else{
! 3274: logIoerr(cnt);
! 3275: }
! 3276: sqlite3_free(zConverted);
! 3277: OSTRACE(("DELETE \"%s\" %s\n", zFilename, (rc ? "failed" : "ok" )));
! 3278: return rc;
! 3279: }
! 3280:
! 3281: /*
! 3282: ** Check the existance and status of a file.
! 3283: */
! 3284: static int winAccess(
! 3285: sqlite3_vfs *pVfs, /* Not used on win32 */
! 3286: const char *zFilename, /* Name of file to check */
! 3287: int flags, /* Type of test to make on this file */
! 3288: int *pResOut /* OUT: Result */
! 3289: ){
! 3290: DWORD attr;
! 3291: int rc = 0;
! 3292: DWORD lastErrno;
! 3293: void *zConverted;
! 3294: UNUSED_PARAMETER(pVfs);
! 3295:
! 3296: SimulateIOError( return SQLITE_IOERR_ACCESS; );
! 3297: zConverted = convertUtf8Filename(zFilename);
! 3298: if( zConverted==0 ){
! 3299: return SQLITE_IOERR_NOMEM;
! 3300: }
! 3301: if( isNT() ){
! 3302: int cnt = 0;
! 3303: WIN32_FILE_ATTRIBUTE_DATA sAttrData;
! 3304: memset(&sAttrData, 0, sizeof(sAttrData));
! 3305: while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
! 3306: GetFileExInfoStandard,
! 3307: &sAttrData)) && retryIoerr(&cnt, &lastErrno) ){}
! 3308: if( rc ){
! 3309: /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file
! 3310: ** as if it does not exist.
! 3311: */
! 3312: if( flags==SQLITE_ACCESS_EXISTS
! 3313: && sAttrData.nFileSizeHigh==0
! 3314: && sAttrData.nFileSizeLow==0 ){
! 3315: attr = INVALID_FILE_ATTRIBUTES;
! 3316: }else{
! 3317: attr = sAttrData.dwFileAttributes;
! 3318: }
! 3319: }else{
! 3320: logIoerr(cnt);
! 3321: if( lastErrno!=ERROR_FILE_NOT_FOUND ){
! 3322: winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess", zFilename);
! 3323: sqlite3_free(zConverted);
! 3324: return SQLITE_IOERR_ACCESS;
! 3325: }else{
! 3326: attr = INVALID_FILE_ATTRIBUTES;
! 3327: }
! 3328: }
! 3329: /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
! 3330: ** Since the ANSI version of these Windows API do not exist for WINCE,
! 3331: ** it's important to not reference them for WINCE builds.
! 3332: */
! 3333: #if SQLITE_OS_WINCE==0
! 3334: }else{
! 3335: attr = osGetFileAttributesA((char*)zConverted);
! 3336: #endif
! 3337: }
! 3338: sqlite3_free(zConverted);
! 3339: switch( flags ){
! 3340: case SQLITE_ACCESS_READ:
! 3341: case SQLITE_ACCESS_EXISTS:
! 3342: rc = attr!=INVALID_FILE_ATTRIBUTES;
! 3343: break;
! 3344: case SQLITE_ACCESS_READWRITE:
! 3345: rc = attr!=INVALID_FILE_ATTRIBUTES &&
! 3346: (attr & FILE_ATTRIBUTE_READONLY)==0;
! 3347: break;
! 3348: default:
! 3349: assert(!"Invalid flags argument");
! 3350: }
! 3351: *pResOut = rc;
! 3352: return SQLITE_OK;
! 3353: }
! 3354:
! 3355:
! 3356: /*
! 3357: ** Turn a relative pathname into a full pathname. Write the full
! 3358: ** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname
! 3359: ** bytes in size.
! 3360: */
! 3361: static int winFullPathname(
! 3362: sqlite3_vfs *pVfs, /* Pointer to vfs object */
! 3363: const char *zRelative, /* Possibly relative input path */
! 3364: int nFull, /* Size of output buffer in bytes */
! 3365: char *zFull /* Output buffer */
! 3366: ){
! 3367:
! 3368: #if defined(__CYGWIN__)
! 3369: SimulateIOError( return SQLITE_ERROR );
! 3370: UNUSED_PARAMETER(nFull);
! 3371: cygwin_conv_to_full_win32_path(zRelative, zFull);
! 3372: return SQLITE_OK;
! 3373: #endif
! 3374:
! 3375: #if SQLITE_OS_WINCE
! 3376: SimulateIOError( return SQLITE_ERROR );
! 3377: UNUSED_PARAMETER(nFull);
! 3378: /* WinCE has no concept of a relative pathname, or so I am told. */
! 3379: sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zRelative);
! 3380: return SQLITE_OK;
! 3381: #endif
! 3382:
! 3383: #if !SQLITE_OS_WINCE && !defined(__CYGWIN__)
! 3384: int nByte;
! 3385: void *zConverted;
! 3386: char *zOut;
! 3387:
! 3388: /* If this path name begins with "/X:", where "X" is any alphabetic
! 3389: ** character, discard the initial "/" from the pathname.
! 3390: */
! 3391: if( zRelative[0]=='/' && sqlite3Isalpha(zRelative[1]) && zRelative[2]==':' ){
! 3392: zRelative++;
! 3393: }
! 3394:
! 3395: /* It's odd to simulate an io-error here, but really this is just
! 3396: ** using the io-error infrastructure to test that SQLite handles this
! 3397: ** function failing. This function could fail if, for example, the
! 3398: ** current working directory has been unlinked.
! 3399: */
! 3400: SimulateIOError( return SQLITE_ERROR );
! 3401: UNUSED_PARAMETER(nFull);
! 3402: zConverted = convertUtf8Filename(zRelative);
! 3403: if( zConverted==0 ){
! 3404: return SQLITE_IOERR_NOMEM;
! 3405: }
! 3406: if( isNT() ){
! 3407: LPWSTR zTemp;
! 3408: nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0) + 3;
! 3409: zTemp = sqlite3_malloc( nByte*sizeof(zTemp[0]) );
! 3410: if( zTemp==0 ){
! 3411: sqlite3_free(zConverted);
! 3412: return SQLITE_IOERR_NOMEM;
! 3413: }
! 3414: osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0);
! 3415: sqlite3_free(zConverted);
! 3416: zOut = unicodeToUtf8(zTemp);
! 3417: sqlite3_free(zTemp);
! 3418: /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
! 3419: ** Since the ANSI version of these Windows API do not exist for WINCE,
! 3420: ** it's important to not reference them for WINCE builds.
! 3421: */
! 3422: #if SQLITE_OS_WINCE==0
! 3423: }else{
! 3424: char *zTemp;
! 3425: nByte = osGetFullPathNameA((char*)zConverted, 0, 0, 0) + 3;
! 3426: zTemp = sqlite3_malloc( nByte*sizeof(zTemp[0]) );
! 3427: if( zTemp==0 ){
! 3428: sqlite3_free(zConverted);
! 3429: return SQLITE_IOERR_NOMEM;
! 3430: }
! 3431: osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
! 3432: sqlite3_free(zConverted);
! 3433: zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
! 3434: sqlite3_free(zTemp);
! 3435: #endif
! 3436: }
! 3437: if( zOut ){
! 3438: sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zOut);
! 3439: sqlite3_free(zOut);
! 3440: return SQLITE_OK;
! 3441: }else{
! 3442: return SQLITE_IOERR_NOMEM;
! 3443: }
! 3444: #endif
! 3445: }
! 3446:
! 3447: #ifndef SQLITE_OMIT_LOAD_EXTENSION
! 3448: /*
! 3449: ** Interfaces for opening a shared library, finding entry points
! 3450: ** within the shared library, and closing the shared library.
! 3451: */
! 3452: /*
! 3453: ** Interfaces for opening a shared library, finding entry points
! 3454: ** within the shared library, and closing the shared library.
! 3455: */
! 3456: static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
! 3457: HANDLE h;
! 3458: void *zConverted = convertUtf8Filename(zFilename);
! 3459: UNUSED_PARAMETER(pVfs);
! 3460: if( zConverted==0 ){
! 3461: return 0;
! 3462: }
! 3463: if( isNT() ){
! 3464: h = osLoadLibraryW((LPCWSTR)zConverted);
! 3465: /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
! 3466: ** Since the ANSI version of these Windows API do not exist for WINCE,
! 3467: ** it's important to not reference them for WINCE builds.
! 3468: */
! 3469: #if SQLITE_OS_WINCE==0
! 3470: }else{
! 3471: h = osLoadLibraryA((char*)zConverted);
! 3472: #endif
! 3473: }
! 3474: sqlite3_free(zConverted);
! 3475: return (void*)h;
! 3476: }
! 3477: static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
! 3478: UNUSED_PARAMETER(pVfs);
! 3479: getLastErrorMsg(osGetLastError(), nBuf, zBufOut);
! 3480: }
! 3481: static void (*winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
! 3482: UNUSED_PARAMETER(pVfs);
! 3483: return (void(*)(void))osGetProcAddressA((HANDLE)pHandle, zSymbol);
! 3484: }
! 3485: static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
! 3486: UNUSED_PARAMETER(pVfs);
! 3487: osFreeLibrary((HANDLE)pHandle);
! 3488: }
! 3489: #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
! 3490: #define winDlOpen 0
! 3491: #define winDlError 0
! 3492: #define winDlSym 0
! 3493: #define winDlClose 0
! 3494: #endif
! 3495:
! 3496:
! 3497: /*
! 3498: ** Write up to nBuf bytes of randomness into zBuf.
! 3499: */
! 3500: static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
! 3501: int n = 0;
! 3502: UNUSED_PARAMETER(pVfs);
! 3503: #if defined(SQLITE_TEST)
! 3504: n = nBuf;
! 3505: memset(zBuf, 0, nBuf);
! 3506: #else
! 3507: if( sizeof(SYSTEMTIME)<=nBuf-n ){
! 3508: SYSTEMTIME x;
! 3509: osGetSystemTime(&x);
! 3510: memcpy(&zBuf[n], &x, sizeof(x));
! 3511: n += sizeof(x);
! 3512: }
! 3513: if( sizeof(DWORD)<=nBuf-n ){
! 3514: DWORD pid = osGetCurrentProcessId();
! 3515: memcpy(&zBuf[n], &pid, sizeof(pid));
! 3516: n += sizeof(pid);
! 3517: }
! 3518: if( sizeof(DWORD)<=nBuf-n ){
! 3519: DWORD cnt = osGetTickCount();
! 3520: memcpy(&zBuf[n], &cnt, sizeof(cnt));
! 3521: n += sizeof(cnt);
! 3522: }
! 3523: if( sizeof(LARGE_INTEGER)<=nBuf-n ){
! 3524: LARGE_INTEGER i;
! 3525: osQueryPerformanceCounter(&i);
! 3526: memcpy(&zBuf[n], &i, sizeof(i));
! 3527: n += sizeof(i);
! 3528: }
! 3529: #endif
! 3530: return n;
! 3531: }
! 3532:
! 3533:
! 3534: /*
! 3535: ** Sleep for a little while. Return the amount of time slept.
! 3536: */
! 3537: static int winSleep(sqlite3_vfs *pVfs, int microsec){
! 3538: osSleep((microsec+999)/1000);
! 3539: UNUSED_PARAMETER(pVfs);
! 3540: return ((microsec+999)/1000)*1000;
! 3541: }
! 3542:
! 3543: /*
! 3544: ** The following variable, if set to a non-zero value, is interpreted as
! 3545: ** the number of seconds since 1970 and is used to set the result of
! 3546: ** sqlite3OsCurrentTime() during testing.
! 3547: */
! 3548: #ifdef SQLITE_TEST
! 3549: int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */
! 3550: #endif
! 3551:
! 3552: /*
! 3553: ** Find the current time (in Universal Coordinated Time). Write into *piNow
! 3554: ** the current time and date as a Julian Day number times 86_400_000. In
! 3555: ** other words, write into *piNow the number of milliseconds since the Julian
! 3556: ** epoch of noon in Greenwich on November 24, 4714 B.C according to the
! 3557: ** proleptic Gregorian calendar.
! 3558: **
! 3559: ** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
! 3560: ** cannot be found.
! 3561: */
! 3562: static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
! 3563: /* FILETIME structure is a 64-bit value representing the number of
! 3564: 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
! 3565: */
! 3566: FILETIME ft;
! 3567: static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000;
! 3568: #ifdef SQLITE_TEST
! 3569: static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
! 3570: #endif
! 3571: /* 2^32 - to avoid use of LL and warnings in gcc */
! 3572: static const sqlite3_int64 max32BitValue =
! 3573: (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + (sqlite3_int64)294967296;
! 3574:
! 3575: #if SQLITE_OS_WINCE
! 3576: SYSTEMTIME time;
! 3577: osGetSystemTime(&time);
! 3578: /* if SystemTimeToFileTime() fails, it returns zero. */
! 3579: if (!osSystemTimeToFileTime(&time,&ft)){
! 3580: return SQLITE_ERROR;
! 3581: }
! 3582: #else
! 3583: osGetSystemTimeAsFileTime( &ft );
! 3584: #endif
! 3585:
! 3586: *piNow = winFiletimeEpoch +
! 3587: ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) +
! 3588: (sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000;
! 3589:
! 3590: #ifdef SQLITE_TEST
! 3591: if( sqlite3_current_time ){
! 3592: *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
! 3593: }
! 3594: #endif
! 3595: UNUSED_PARAMETER(pVfs);
! 3596: return SQLITE_OK;
! 3597: }
! 3598:
! 3599: /*
! 3600: ** Find the current time (in Universal Coordinated Time). Write the
! 3601: ** current time and date as a Julian Day number into *prNow and
! 3602: ** return 0. Return 1 if the time and date cannot be found.
! 3603: */
! 3604: static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
! 3605: int rc;
! 3606: sqlite3_int64 i;
! 3607: rc = winCurrentTimeInt64(pVfs, &i);
! 3608: if( !rc ){
! 3609: *prNow = i/86400000.0;
! 3610: }
! 3611: return rc;
! 3612: }
! 3613:
! 3614: /*
! 3615: ** The idea is that this function works like a combination of
! 3616: ** GetLastError() and FormatMessage() on Windows (or errno and
! 3617: ** strerror_r() on Unix). After an error is returned by an OS
! 3618: ** function, SQLite calls this function with zBuf pointing to
! 3619: ** a buffer of nBuf bytes. The OS layer should populate the
! 3620: ** buffer with a nul-terminated UTF-8 encoded error message
! 3621: ** describing the last IO error to have occurred within the calling
! 3622: ** thread.
! 3623: **
! 3624: ** If the error message is too large for the supplied buffer,
! 3625: ** it should be truncated. The return value of xGetLastError
! 3626: ** is zero if the error message fits in the buffer, or non-zero
! 3627: ** otherwise (if the message was truncated). If non-zero is returned,
! 3628: ** then it is not necessary to include the nul-terminator character
! 3629: ** in the output buffer.
! 3630: **
! 3631: ** Not supplying an error message will have no adverse effect
! 3632: ** on SQLite. It is fine to have an implementation that never
! 3633: ** returns an error message:
! 3634: **
! 3635: ** int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
! 3636: ** assert(zBuf[0]=='\0');
! 3637: ** return 0;
! 3638: ** }
! 3639: **
! 3640: ** However if an error message is supplied, it will be incorporated
! 3641: ** by sqlite into the error message available to the user using
! 3642: ** sqlite3_errmsg(), possibly making IO errors easier to debug.
! 3643: */
! 3644: static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
! 3645: UNUSED_PARAMETER(pVfs);
! 3646: return getLastErrorMsg(osGetLastError(), nBuf, zBuf);
! 3647: }
! 3648:
! 3649: /*
! 3650: ** Initialize and deinitialize the operating system interface.
! 3651: */
! 3652: int sqlite3_os_init(void){
! 3653: static sqlite3_vfs winVfs = {
! 3654: 3, /* iVersion */
! 3655: sizeof(winFile), /* szOsFile */
! 3656: MAX_PATH, /* mxPathname */
! 3657: 0, /* pNext */
! 3658: "win32", /* zName */
! 3659: 0, /* pAppData */
! 3660: winOpen, /* xOpen */
! 3661: winDelete, /* xDelete */
! 3662: winAccess, /* xAccess */
! 3663: winFullPathname, /* xFullPathname */
! 3664: winDlOpen, /* xDlOpen */
! 3665: winDlError, /* xDlError */
! 3666: winDlSym, /* xDlSym */
! 3667: winDlClose, /* xDlClose */
! 3668: winRandomness, /* xRandomness */
! 3669: winSleep, /* xSleep */
! 3670: winCurrentTime, /* xCurrentTime */
! 3671: winGetLastError, /* xGetLastError */
! 3672: winCurrentTimeInt64, /* xCurrentTimeInt64 */
! 3673: winSetSystemCall, /* xSetSystemCall */
! 3674: winGetSystemCall, /* xGetSystemCall */
! 3675: winNextSystemCall, /* xNextSystemCall */
! 3676: };
! 3677:
! 3678: /* Double-check that the aSyscall[] array has been constructed
! 3679: ** correctly. See ticket [bb3a86e890c8e96ab] */
! 3680: assert( ArraySize(aSyscall)==60 );
! 3681:
! 3682: #ifndef SQLITE_OMIT_WAL
! 3683: /* get memory map allocation granularity */
! 3684: memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
! 3685: osGetSystemInfo(&winSysInfo);
! 3686: assert(winSysInfo.dwAllocationGranularity > 0);
! 3687: #endif
! 3688:
! 3689: sqlite3_vfs_register(&winVfs, 1);
! 3690: return SQLITE_OK;
! 3691: }
! 3692:
! 3693: int sqlite3_os_end(void){
! 3694: return SQLITE_OK;
! 3695: }
! 3696:
! 3697: #endif /* SQLITE_OS_WIN */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>