/Languages/IronPython/IronPython.SQLite/c#sqlite/os_win_c.cs
C# | 3829 lines | 2285 code | 271 blank | 1273 comment | 456 complexity | a0f0d7b8e136ce4a90f18e2577dbfb2d MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
Large files files are truncated, but you can click here to view the full file
- #define SQLITE_OS_WIN
- using System;
- using System.Diagnostics;
- using System.IO;
- using System.Runtime.InteropServices;
- using System.Text;
- using System.Threading;
- using DWORD = System.UInt64;
- using HANDLE = System.IntPtr;
- using i64 = System.Int64;
- using sqlite3_int64 = System.Int64;
- using u32 = System.UInt32;
- using u8 = System.Byte;
- #if SQLITE_WINRT
- using System.Threading.Tasks;
- using Windows.Storage;
- using Windows.Storage.Streams;
- using System.Runtime.InteropServices.WindowsRuntime;
- #elif WINDOWS_PHONE || SQLITE_SILVERLIGHT
- using System.IO.IsolatedStorage;
- #endif
- #if NETCOREAPP1_0
- using Environment = System.FakeEnvironment;
- #endif
- namespace Community.CsharpSqlite
- {
- public partial class Sqlite3
- {
- /*
- ** 2004 May 22
- **
- ** The author disclaims copyright to this source code. In place of
- ** a legal notice, here is a blessing:
- **
- ** May you do good and not evil.
- ** May you find forgiveness for yourself and forgive others.
- ** May you share freely, never taking more than you give.
- **
- ******************************************************************************
- **
- ** This file contains code that is specific to windows.
- *************************************************************************
- ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
- ** C#-SQLite is an independent reimplementation of the SQLite software library
- **
- ** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
- **
- *************************************************************************
- */
- //#include "sqliteInt.h"
- #if SQLITE_OS_WIN // * This file is used for windows only */
- /*
- ** A Note About Memory Allocation:
- **
- ** This driver uses malloc()/free() directly rather than going through
- ** the SQLite-wrappers sqlite3Malloc()/sqlite3DbFree(db,ref ). Those wrappers
- ** are designed for use on embedded systems where memory is scarce and
- ** malloc failures happen frequently. Win32 does not typically run on
- ** embedded systems, and when it does the developers normally have bigger
- ** problems to worry about than running out of memory. So there is not
- ** a compelling need to use the wrappers.
- **
- ** But there is a good reason to not use the wrappers. If we use the
- ** wrappers then we will get simulated malloc() failures within this
- ** driver. And that causes all kinds of problems for our tests. We
- ** could enhance SQLite to deal with simulated malloc failures within
- ** the OS driver, but the code to deal with those failure would not
- ** be exercised on Linux (which does not need to malloc() in the driver)
- ** and so we would have difficulty writing coverage tests for that
- ** code. Better to leave the code out, we think.
- **
- ** The point of this discussion is as follows: When creating a new
- ** OS layer for an embedded system, if you use this file as an example,
- ** avoid the use of malloc()/free(). Those routines work ok on windows
- ** desktops but not so well in embedded systems.
- */
- //#include <winbase.h>
- #if __CYGWIN__
- //# include <sys/cygwin.h>
- #endif
- /*
- ** Macros used to determine whether or not to use threads.
- */
- #if THREADSAFE
- //# define SQLITE_W32_THREADS 1
- #endif
- /*
- ** Include code that is common to all os_*.c files
- */
- //#include "os_common.h"
- /*
- ** Some microsoft compilers lack this definition.
- */
- #if !INVALID_FILE_ATTRIBUTES
- //# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
- const int INVALID_FILE_ATTRIBUTES = -1;
- #endif
- /*
- ** Determine if we are dealing with WindowsCE - which has a much
- ** reduced API.
- */
- #if SQLITE_OS_WINCE
- //# define AreFileApisANSI() 1
- //# define GetDiskFreeSpaceW() 0
- #endif
- /* Forward references */
- //typedef struct winShm winShm; /* A connection to shared-memory */
- //typedef struct winShmNode winShmNode; /* A region of shared-memory */
- /*
- ** WinCE lacks native support for file locking so we have to fake it
- ** with some code of our own.
- */
- #if SQLITE_OS_WINCE
- typedef struct winceLock {
- int nReaders; /* Number of reader locks obtained */
- BOOL bPending; /* Indicates a pending lock has been obtained */
- BOOL bReserved; /* Indicates a reserved lock has been obtained */
- BOOL bExclusive; /* Indicates an exclusive lock has been obtained */
- } winceLock;
- #endif
- private static LockingStrategy lockingStrategy = HelperMethods.IsRunningMediumTrust() ? new MediumTrustLockingStrategy() : new LockingStrategy();
- /*
- ** The winFile structure is a subclass of sqlite3_file* specific to the win32
- ** portability layer.
- */
- //typedef struct sqlite3_file sqlite3_file;
- public partial class sqlite3_file
- {
- public sqlite3_vfs pVfs; /* The VFS used to open this file */
- #if SQLITE_WINRT
- public IRandomAccessStream fs;
- #else
- public FileStream fs; /* Filestream access to this file*/
- #endif
- // public HANDLE h; /* Handle for accessing the file */
- public int locktype; /* Type of lock currently held on this file */
- public int sharedLockByte; /* Randomly chosen byte used as a shared lock */
- public DWORD lastErrno; /* The Windows errno from the last I/O error */
- public DWORD sectorSize; /* Sector size of the device file is on */
- #if !SQLITE_OMIT_WAL
- public winShm pShm; /* Instance of shared memory on this file */
- #else
- public object pShm; /* DUMMY Instance of shared memory on this file */
- #endif
- public string zPath; /* Full pathname of this file */
- public int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */
- #if SQLITE_OS_WINCE
- Wstring zDeleteOnClose; /* Name of file to delete when closing */
- HANDLE hMutex; /* Mutex used to control access to shared lock */
- HANDLE hShared; /* Shared memory segment used for locking */
- winceLock local; /* Locks obtained by this instance of sqlite3_file */
- winceLock *shared; /* Global shared lock memory for the file */
- #endif
- public void Clear()
- {
- pMethods = null;
- fs = null;
- locktype = 0;
- sharedLockByte = 0;
- lastErrno = 0;
- sectorSize = 0;
- }
- };
- /*
- ** Forward prototypes.
- */
- //static int getSectorSize(
- // sqlite3_vfs *pVfs,
- // string zRelative /* UTF-8 file name */
- //);
- /*
- ** The following variable is (normally) set once and never changes
- ** thereafter. It records whether the operating system is Win95
- ** or WinNT.
- **
- ** 0: Operating system unknown.
- ** 1: Operating system is Win95.
- ** 2: Operating system is WinNT.
- **
- ** In order to facilitate testing on a WinNT system, the test fixture
- ** can manually set this value to 1 to emulate Win98 behavior.
- */
- #if SQLITE_TEST
- int sqlite3_os_type = 0;
- #else
- static int sqlite3_os_type = 0;
- #endif
- /*
- ** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
- ** or WinCE. Return false (zero) for Win95, Win98, or WinME.
- **
- ** Here is an interesting observation: Win95, Win98, and WinME lack
- ** the LockFileEx() API. But we can still statically link against that
- ** API as long as we don't call it when running Win95/98/ME. A call to
- ** this routine is used to determine if the host is Win95/98/ME or
- ** WinNT/2K/XP so that we will know whether or not we can safely call
- ** the LockFileEx() API.
- */
- #if SQLITE_OS_WINCE
- //# define isNT() (1)
- #elif SQLITE_WINRT
- static bool isNT() { return true; }
- #else
- static bool isNT()
- {
- //if (sqlite3_os_type == 0)
- //{
- // OSVERSIONINFO sInfo;
- // sInfo.dwOSVersionInfoSize = sInfo.Length;
- // GetVersionEx(&sInfo);
- // sqlite3_os_type = sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ? 2 : 1;
- //}
- //return sqlite3_os_type == 2;
- return Environment.OSVersion.Platform >= PlatformID.Win32NT;
- }
- #endif // * SQLITE_OS_WINCE */
- /*
- ** Convert a UTF-8 string to microsoft unicode (UTF-16?).
- **
- ** Space to hold the returned string is obtained from malloc.
- */
- //static WCHAR *utf8ToUnicode(string zFilename){
- // int nChar;
- // Wstring zWideFilename;
- // nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
- // zWideFilename = malloc( nChar*sizeof(zWideFilename[0]) );
- // if( zWideFilename==0 ){
- // return 0;
- // }
- // nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar);
- // if( nChar==0 ){
- // free(zWideFilename);
- // zWideFileName = "";
- // }
- // return zWideFilename;
- //}
- /*
- ** Convert microsoft unicode to UTF-8. Space to hold the returned string is
- ** obtained from malloc().
- */
- //static char *unicodeToUtf8(const Wstring zWideFilename){
- // int nByte;
- // string zFilename;
- // nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
- // zFilename = malloc( nByte );
- // if( zFilename==0 ){
- // return 0;
- // }
- // nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
- // 0, 0);
- // if( nByte == 0 ){
- // free(zFilename);
- // zFileName = "";
- // }
- // return zFilename;
- //}
- /*
- ** Convert an ansi string to microsoft unicode, based on the
- ** current codepage settings for file apis.
- **
- ** Space to hold the returned string is obtained
- ** from malloc.
- */
- //static WCHAR *mbcsToUnicode(string zFilename){
- // int nByte;
- // Wstring zMbcsFilename;
- // int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
- // nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, NULL,0)*WCHAR.Length;
- // zMbcsFilename = malloc( nByte*sizeof(zMbcsFilename[0]) );
- // if( zMbcsFilename==0 ){
- // return 0;
- // }
- // nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename, nByte);
- // if( nByte==0 ){
- // free(zMbcsFilename);
- // zMbcsFileName = "";
- // }
- // return zMbcsFilename;
- //}
- /*
- ** Convert microsoft unicode to multibyte character string, based on the
- ** user's Ansi codepage.
- **
- ** Space to hold the returned string is obtained from
- ** malloc().
- */
- //static char *unicodeToMbcs(const Wstring zWideFilename){
- // int nByte;
- // string zFilename;
- // int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
- // nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
- // zFilename = malloc( nByte );
- // if( zFilename==0 ){
- // return 0;
- // }
- // nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename, nByte,
- // 0, 0);
- // if( nByte == 0 ){
- // free(zFilename);
- // zFileName = "";
- // }
- // return zFilename;
- //}
- /*
- ** Convert multibyte character string to UTF-8. Space to hold the
- ** returned string is obtained from malloc().
- */
- //static char *sqlite3_win32_mbcs_to_utf8(string zFilename){
- // string zFilenameUtf8;
- // Wstring zTmpWide;
- // zTmpWide = mbcsToUnicode(zFilename);
- // if( zTmpWide==0 ){
- // return 0;
- // }
- // zFilenameUtf8 = unicodeToUtf8(zTmpWide);
- // free(zTmpWide);
- // return zFilenameUtf8;
- //}
- /*
- ** Convert UTF-8 to multibyte character string. Space to hold the
- ** returned string is obtained from malloc().
- */
- //char *sqlite3_win32_utf8_to_mbcs(string zFilename){
- // string zFilenameMbcs;
- // Wstring zTmpWide;
- // zTmpWide = utf8ToUnicode(zFilename);
- // if( zTmpWide==0 ){
- // return 0;
- // }
- // zFilenameMbcs = unicodeToMbcs(zTmpWide);
- // free(zTmpWide);
- // return zFilenameMbcs;
- //}
- /*
- ** The return value of getLastErrorMsg
- ** is zero if the error message fits in the buffer, or non-zero
- ** otherwise (if the message was truncated).
- */
- static int getLastErrorMsg(int nBuf, ref string zBuf){
- /* FormatMessage returns 0 on failure. Otherwise it
- ** returns the number of TCHARs written to the output
- ** buffer, excluding the terminating null char.
- */
- //DWORD error = GetLastError();
- //DWORD dwLen = 0;
- //string zOut = "";
- //if( isNT() ){
- //Wstring zTempWide = NULL;
- //dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- // NULL,
- // error,
- // 0,
- // (LPWSTR) &zTempWide,
- // 0,
- // 0);
- #if SQLITE_SILVERLIGHT || SQLITE_WINRT
- zBuf = "Unknown error";
- #else
- zBuf = Marshal.GetLastWin32Error().ToString();//new Win32Exception( Marshal.GetLastWin32Error() ).Message;
- #endif
- //if( dwLen > 0 ){
- // /* allocate a buffer and convert to UTF8 */
- // zOut = unicodeToUtf8(zTempWide);
- // /* free the system buffer allocated by FormatMessage */
- // LocalFree(zTempWide);
- //}
- /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
- ** Since the ASCII version of these Windows API do not exist for WINCE,
- ** it's important to not reference them for WINCE builds.
- */
- //#if !SQLITE_OS_WINCE //==0
- // }else{
- // string zTemp = null;
- // dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- // null,
- // error,
- // 0,
- // ref zTemp,
- // 0,
- // 0);
- // if( dwLen > 0 ){
- // /* allocate a buffer and convert to UTF8 */
- // zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
- // /* free the system buffer allocated by FormatMessage */
- // LocalFree(zTemp);
- // }
- //#endif
- // }
- //if( 0 == dwLen ){
- // sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error);
- //}else{
- // /* copy a maximum of nBuf chars to output buffer */
- // sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
- // /* free the UTF8 buffer */
- // free(zOut);
- //}
- return 0;
- }
- /*
- **
- ** This function - winLogErrorAtLine() - is only ever called via the macro
- ** winLogError().
- **
- ** This routine is invoked after an error occurs in an OS function.
- ** It logs a message using sqlite3_log() containing the current value of
- ** error code and, if possible, the human-readable equivalent from
- ** FormatMessage.
- **
- ** The first argument passed to the macro should be the error code that
- ** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN).
- ** The two subsequent arguments should be the name of the OS function that
- ** failed and the the associated file-system path, if any.
- */
- //#define winLogError(a,b,c) winLogErrorAtLine(a,b,c,__LINE__)
- static int winLogError( int a, string b, string c )
- {
- #if !SQLITE_WINRT && !SILVERLIGHT && !NETSTANDARD
- StackTrace st = new StackTrace( new StackFrame( true ) );
- StackFrame sf = st.GetFrame( 0 );
-
- return winLogErrorAtLine( a, b, c, sf.GetFileLineNumber() );
- #else
- return winLogErrorAtLine( a, b, c, 0 );
- #endif
- }
- static int winLogErrorAtLine(
- int errcode, /* SQLite error code */
- string zFunc, /* Name of OS function that failed */
- string zPath, /* File path associated with error */
- int iLine /* Source line number where error occurred */
- ){
- string zMsg = null; /* Human readable error text */
- int i; /* Loop counter */
- DWORD iErrno;// = GetLastError(); /* Error code */
- #if SQLITE_SILVERLIGHT || SQLITE_WINRT
- iErrno = (int)ERROR_NOT_SUPPORTED;
- #else
- iErrno = (u32)Marshal.GetLastWin32Error();
- #endif
- //zMsg[0] = 0;
- getLastErrorMsg( 500, ref zMsg );
- Debug.Assert( errcode != SQLITE_OK );
- if ( zPath == null )
- zPath = "";
- for ( i = 0; i < zMsg.Length && zMsg[i] != '\r' && zMsg[i] != '\n'; i++ )
- {
- }
- zMsg = zMsg.Substring( 0, i );
- sqlite3_log(errcode,
- "os_win.c:%d: (%d) %s(%s) - %s",
- iLine, iErrno, zFunc, zPath, zMsg
- );
- return errcode;
- }
- #if SQLITE_OS_WINCE
- /*************************************************************************
- ** This section contains code for WinCE only.
- */
- /*
- ** WindowsCE does not have a localtime() function. So create a
- ** substitute.
- */
- //#include <time.h>
- struct tm *__cdecl localtime(const time_t *t)
- {
- static struct tm y;
- FILETIME uTm, lTm;
- SYSTEMTIME pTm;
- sqlite3_int64 t64;
- t64 = *t;
- t64 = (t64 + 11644473600)*10000000;
- uTm.dwLowDateTime = (DWORD)(t64 & 0xFFFFFFFF);
- uTm.dwHighDateTime= (DWORD)(t64 >> 32);
- FileTimeToLocalFileTime(&uTm,&lTm);
- FileTimeToSystemTime(&lTm,&pTm);
- y.tm_year = pTm.wYear - 1900;
- y.tm_mon = pTm.wMonth - 1;
- y.tm_wday = pTm.wDayOfWeek;
- y.tm_mday = pTm.wDay;
- y.tm_hour = pTm.wHour;
- y.tm_min = pTm.wMinute;
- y.tm_sec = pTm.wSecond;
- return &y;
- }
- /* This will never be called, but defined to make the code compile */
- //#define GetTempPathA(a,b)
- //#define LockFile(a,b,c,d,e) winceLockFile(&a, b, c, d, e)
- //#define UnlockFile(a,b,c,d,e) winceUnlockFile(&a, b, c, d, e)
- //#define LockFileEx(a,b,c,d,e,f) winceLockFileEx(&a, b, c, d, e, f)
- //#define HANDLE_TO_WINFILE(a) (winFile)&((char)a)[-(int)offsetof(winFile,h)]
- /*
- ** Acquire a lock on the handle h
- */
- static void winceMutexAcquire(HANDLE h){
- DWORD dwErr;
- do {
- dwErr = WaitForSingleObject(h, INFINITE);
- } while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED);
- }
- /*
- ** Release a lock acquired by winceMutexAcquire()
- */
- //#define winceMutexRelease(h) ReleaseMutex(h)
- /*
- ** Create the mutex and shared memory used for locking in the file
- ** descriptor pFile
- */
- static BOOL winceCreateLock(string zFilename, sqlite3_file pFile){
- Wstring zTok;
- Wstring zName = utf8ToUnicode(zFilename);
- BOOL bInit = TRUE;
- /* Initialize the local lockdata */
- ZeroMemory(pFile.local, pFile.local).Length;
- /* Replace the backslashes from the filename and lowercase it
- ** to derive a mutex name. */
- zTok = CharLowerW(zName);
- for (;*zTok;zTok++){
- if (*zTok == '\\') *zTok = '_';
- }
- /* Create/open the named mutex */
- pFile.hMutex = CreateMutexW(NULL, FALSE, zName);
- if (!pFile.hMutex){
- pFile.lastErrno = (u32)GetLastError();
- winLogError(SQLITE_ERROR, "winceCreateLock1", zFilename);
- free(zName);
- return FALSE;
- }
- /* Acquire the mutex before continuing */
- winceMutexAcquire(pFile.hMutex);
- /* Since the names of named mutexes, semaphores, file mappings etc are
- ** case-sensitive, take advantage of that by uppercasing the mutex name
- ** and using that as the shared filemapping name.
- */
- CharUpperW(zName);
- pFile.hShared = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
- PAGE_READWRITE, 0, winceLock.Length,
- zName);
- /* Set a flag that indicates we're the first to create the memory so it
- ** must be zero-initialized */
- if (GetLastError() == ERROR_ALREADY_EXISTS){
- bInit = FALSE;
- }
- free(zName);
- /* If we succeeded in making the shared memory handle, map it. */
- if (pFile.hShared){
- pFile.shared = (winceLock)MapViewOfFile(pFile.hShared,
- FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, winceLock).Length;
- /* If mapping failed, close the shared memory handle and erase it */
- if (!pFile.shared){
- pFile.lastErrno = (u32)GetLastError();
- winLogError(SQLITE_ERROR, "winceCreateLock2", zFilename);
- CloseHandle(pFile.hShared);
- pFile.hShared = NULL;
- }
- }
- /* If shared memory could not be created, then close the mutex and fail */
- if (pFile.hShared == NULL){
- winceMutexRelease(pFile.hMutex);
- CloseHandle(pFile.hMutex);
- pFile.hMutex = NULL;
- return FALSE;
- }
- /* Initialize the shared memory if we're supposed to */
- if (bInit) {
- ZeroMemory(pFile.shared, winceLock).Length;
- }
- winceMutexRelease(pFile.hMutex);
- return TRUE;
- }
- /*
- ** Destroy the part of sqlite3_file that deals with wince locks
- */
- static void winceDestroyLock(sqlite3_file pFile){
- if (pFile.hMutex){
- /* Acquire the mutex */
- winceMutexAcquire(pFile.hMutex);
- /* The following blocks should probably Debug.Assert in debug mode, but they
- are to cleanup in case any locks remained open */
- if (pFile.local.nReaders){
- pFile.shared.nReaders --;
- }
- if (pFile.local.bReserved){
- pFile.shared.bReserved = FALSE;
- }
- if (pFile.local.bPending){
- pFile.shared.bPending = FALSE;
- }
- if (pFile.local.bExclusive){
- pFile.shared.bExclusive = FALSE;
- }
- /* De-reference and close our copy of the shared memory handle */
- UnmapViewOfFile(pFile.shared);
- CloseHandle(pFile.hShared);
- /* Done with the mutex */
- winceMutexRelease(pFile.hMutex);
- CloseHandle(pFile.hMutex);
- pFile.hMutex = NULL;
- }
- }
- /*
- ** An implementation of the LockFile() API of windows for wince
- */
- static BOOL winceLockFile(
- HANDLE *phFile,
- DWORD dwFileOffsetLow,
- DWORD dwFileOffsetHigh,
- DWORD nNumberOfBytesToLockLow,
- DWORD nNumberOfBytesToLockHigh
- ){
- winFile *pFile = HANDLE_TO_WINFILE(phFile);
- BOOL bReturn = FALSE;
- UNUSED_PARAMETER(dwFileOffsetHigh);
- UNUSED_PARAMETER(nNumberOfBytesToLockHigh);
- if (!pFile.hMutex) return TRUE;
- winceMutexAcquire(pFile.hMutex);
- /* Wanting an exclusive lock? */
- if (dwFileOffsetLow == (DWORD)SHARED_FIRST
- && nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){
- if (pFile.shared.nReaders == 0 && pFile.shared.bExclusive == 0){
- pFile.shared.bExclusive = TRUE;
- pFile.local.bExclusive = TRUE;
- bReturn = TRUE;
- }
- }
- /* Want a read-only lock? */
- else if (dwFileOffsetLow == (DWORD)SHARED_FIRST &&
- nNumberOfBytesToLockLow == 1){
- if (pFile.shared.bExclusive == 0){
- pFile.local.nReaders ++;
- if (pFile.local.nReaders == 1){
- pFile.shared.nReaders ++;
- }
- bReturn = TRUE;
- }
- }
- /* Want a pending lock? */
- else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToLockLow == 1){
- /* If no pending lock has been acquired, then acquire it */
- if (pFile.shared.bPending == 0) {
- pFile.shared.bPending = TRUE;
- pFile.local.bPending = TRUE;
- bReturn = TRUE;
- }
- }
- /* Want a reserved lock? */
- else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToLockLow == 1){
- if (pFile.shared.bReserved == 0) {
- pFile.shared.bReserved = TRUE;
- pFile.local.bReserved = TRUE;
- bReturn = TRUE;
- }
- }
- winceMutexRelease(pFile.hMutex);
- return bReturn;
- }
- /*
- ** An implementation of the UnlockFile API of windows for wince
- */
- static BOOL winceUnlockFile(
- HANDLE *phFile,
- DWORD dwFileOffsetLow,
- DWORD dwFileOffsetHigh,
- DWORD nNumberOfBytesToUnlockLow,
- DWORD nNumberOfBytesToUnlockHigh
- ){
- winFile *pFile = HANDLE_TO_WINFILE(phFile);
- BOOL bReturn = FALSE;
- UNUSED_PARAMETER(dwFileOffsetHigh);
- UNUSED_PARAMETER(nNumberOfBytesToUnlockHigh);
- if (!pFile.hMutex) return TRUE;
- winceMutexAcquire(pFile.hMutex);
- /* Releasing a reader lock or an exclusive lock */
- if (dwFileOffsetLow == (DWORD)SHARED_FIRST){
- /* Did we have an exclusive lock? */
- if (pFile.local.bExclusive){
- Debug.Assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE);
- pFile.local.bExclusive = FALSE;
- pFile.shared.bExclusive = FALSE;
- bReturn = TRUE;
- }
- /* Did we just have a reader lock? */
- else if (pFile.local.nReaders){
- Debug.Assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE || nNumberOfBytesToUnlockLow == 1);
- pFile.local.nReaders --;
- if (pFile.local.nReaders == 0)
- {
- pFile.shared.nReaders --;
- }
- bReturn = TRUE;
- }
- }
- /* Releasing a pending lock */
- else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToUnlockLow == 1){
- if (pFile.local.bPending){
- pFile.local.bPending = FALSE;
- pFile.shared.bPending = FALSE;
- bReturn = TRUE;
- }
- }
- /* Releasing a reserved lock */
- else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1){
- if (pFile.local.bReserved) {
- pFile.local.bReserved = FALSE;
- pFile.shared.bReserved = FALSE;
- bReturn = TRUE;
- }
- }
- winceMutexRelease(pFile.hMutex);
- return bReturn;
- }
- /*
- ** An implementation of the LockFileEx() API of windows for wince
- */
- static BOOL winceLockFileEx(
- HANDLE *phFile,
- DWORD dwFlags,
- DWORD dwReserved,
- DWORD nNumberOfBytesToLockLow,
- DWORD nNumberOfBytesToLockHigh,
- LPOVERLAPPED lpOverlapped
- ){
- UNUSED_PARAMETER(dwReserved);
- UNUSED_PARAMETER(nNumberOfBytesToLockHigh);
- /* If the caller wants a shared read lock, forward this call
- ** to winceLockFile */
- if (lpOverlapped.Offset == (DWORD)SHARED_FIRST &&
- dwFlags == 1 &&
- nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){
- return winceLockFile(phFile, SHARED_FIRST, 0, 1, 0);
- }
- return FALSE;
- }
- /*
- ** End of the special code for wince
- *****************************************************************************/
- #endif // * SQLITE_OS_WINCE */
- /*****************************************************************************
- ** The next group of routines implement the I/O methods specified
- ** by the sqlite3_io_methods object.
- ******************************************************************************/
- /*
- ** Some microsoft compilers lack this definition.
- */
- #if !INVALID_SET_FILE_POINTER
- //# define INVALID_SET_FILE_POINTER ((DWORD)-1)
- const int INVALID_SET_FILE_POINTER = -1;
- #endif
- /*
- ** Move the current position of the file handle passed as the first
- ** argument to offset iOffset within the file. If successful, return 0.
- ** Otherwise, set pFile->lastErrno and return non-zero.
- */
- static int seekWinFile( sqlite3_file id, sqlite3_int64 iOffset )
- {
- //LONG upperBits; /* Most sig. 32 bits of new offset */
- //LONG lowerBits; /* Least sig. 32 bits of new offset */
- DWORD dwRet; /* Value returned by SetFilePointer() */
- sqlite3_file pFile = id;
- //upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
- //lowerBits = (LONG)(iOffset & 0xffffffff);
- /* API oddity: If successful, SetFilePointer() returns a dword
- ** containing the lower 32-bits of the new file-offset. Or, if it fails,
- ** it returns INVALID_SET_FILE_POINTER. However according to MSDN,
- ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine
- ** whether an error has actually occured, it is also necessary to call
- ** GetLastError().
- */
- //dwRet = SetFilePointer(id, lowerBits, &upperBits, FILE_BEGIN);
- //if( (dwRet==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) ){
- // pFile->lastErrno = GetLastError();
- // winLogError(SQLITE_IOERR_SEEK, "seekWinFile", pFile->zPath);
- try
- {
- #if SQLITE_WINRT
- id.fs.Seek( (ulong)iOffset ); // SetFilePointer(pFile.fs.Name, lowerBits, upperBits, FILE_BEGIN);
- #else
- id.fs.Seek( iOffset, SeekOrigin.Begin ); // SetFilePointer(pFile.fs.Name, lowerBits, upperBits, FILE_BEGIN);
- #endif
- }
- catch ( Exception e )
- {
- #if SQLITE_SILVERLIGHT || SQLITE_WINRT
- pFile.lastErrno = 1;
- #else
- pFile.lastErrno = (u32)Marshal.GetLastWin32Error();
- #endif
- winLogError(SQLITE_IOERR_SEEK, "seekWinFile", pFile.zPath);
- return 1;
- }
- return 0;
- }
- /*
- ** Close a file.
- **
- ** It is reported that an attempt to close a handle might sometimes
- ** fail. This is a very unreasonable result, but windows is notorious
- ** for being unreasonable so I do not doubt that it might happen. If
- ** the close fails, we pause for 100 milliseconds and try again. As
- ** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before
- ** giving up and returning an error.
- */
- public static int MX_CLOSE_ATTEMPT = 3;
- static int winClose( sqlite3_file id )
- {
- bool rc;
- int cnt = 0;
- sqlite3_file pFile = (sqlite3_file)id;
- Debug.Assert( id != null );
- Debug.Assert( pFile.pShm == null );
- #if SQLITE_DEBUG
- #if WINDOWS_PHONE || SQLITE_SILVERLIGHT
- OSTRACE( "CLOSE %d\n", pFile.fs.GetHashCode());
- #else
- OSTRACE( "CLOSE %d (%s)\n", pFile.fs.GetHashCode(), pFile.fs.Name );
- #endif
- #endif
- do
- {
- #if SQLITE_WINRT || NETSTANDARD
- pFile.fs.Dispose();
- #else
- pFile.fs.Close();
- #endif
- rc = true;
- // rc = CloseHandle(pFile.h);
- /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */
- // if (!rc && ++cnt < MX_CLOSE_ATTEMPT) Thread.Sleep(100); //, 1) );
- } while ( !rc && ++cnt < MX_CLOSE_ATTEMPT ); //, 1) );
- #if SQLITE_OS_WINCE
- //#define WINCE_DELETION_ATTEMPTS 3
- winceDestroyLock(pFile);
- if( pFile.zDeleteOnClose ){
- int cnt = 0;
- while(
- DeleteFileW(pFile.zDeleteOnClose)==0
- && GetFileAttributesW(pFile.zDeleteOnClose)!=0xffffffff
- && cnt++ < WINCE_DELETION_ATTEMPTS
- ){
- Sleep(100); /* Wait a little before trying again */
- }
- free(pFile.zDeleteOnClose);
- }
- #endif
- #if SQLITE_TEST
- OSTRACE( "CLOSE %d %s\n", pFile.fs.GetHashCode(), rc ? "ok" : "failed" );
- OpenCounter( -1 );
- #endif
- return rc ? SQLITE_OK : winLogError(SQLITE_IOERR_CLOSE, "winClose", pFile.zPath);
- }
- /*
- ** Read data from a file into a buffer. Return SQLITE_OK if all
- ** bytes were read successfully and SQLITE_IOERR if anything goes
- ** wrong.
- */
- static int winRead(
- sqlite3_file id, /* File to read from */
- byte[] pBuf, /* Write content into this buffer */
- int amt, /* Number of bytes to read */
- sqlite3_int64 offset /* Begin reading at this offset */
- )
- {
- long rc;
- sqlite3_file pFile = id;
- int nRead; /* Number of bytes actually read from file */
- Debug.Assert( id != null );
- #if SQLITE_TEST
- if ( SimulateIOError() )
- return SQLITE_IOERR_READ;
- #endif
- #if SQLITE_DEBUG
- OSTRACE( "READ %d lock=%d\n", pFile.fs.GetHashCode(), pFile.locktype );
- #endif
- if ( !id.fs.CanRead )
- return SQLITE_IOERR_READ;
- if ( seekWinFile( pFile, offset ) != 0 )
- {
- return SQLITE_FULL;
- }
- try
- {
- #if SQLITE_WINRT
- using (IInputStream inputStream = id.fs.GetInputStreamAt((ulong)offset))
- {
- IBuffer buffer = pBuf.AsBuffer(0,0,pBuf.Length);
- inputStream.ReadAsync(buffer, (uint)amt, InputStreamOptions.None).AsTask().Wait();
- nRead = (int)buffer.Length;
- }
- #else
- nRead = id.fs.Read( pBuf, 0, amt ); // i if( null==ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
- #endif
- }
- catch ( Exception e )
- {
- #if SQLITE_SILVERLIGHT || SQLITE_WINRT
- pFile.lastErrno = 1;
- #else
- pFile.lastErrno = (u32)Marshal.GetLastWin32Error();
- #endif
- return winLogError(SQLITE_IOERR_READ, "winRead", pFile.zPath);
- }
- if ( nRead < amt )
- {
- /* Unread parts of the buffer must be zero-filled */
- Array.Clear( pBuf, (int)nRead, (int)( amt - nRead ) ); // memset(&((char)pBuf)[nRead], 0, amt-nRead);
- return SQLITE_IOERR_SHORT_READ;
- }
- return SQLITE_OK;
- }
- /*
- ** Write data from a buffer into a file. Return SQLITE_OK on success
- ** or some other error code on failure.
- */
- static int winWrite(
- sqlite3_file id, /* File to write into */
- byte[] pBuf, /* The bytes to be written */
- int amt, /* Number of bytes to write */
- sqlite3_int64 offset /* Offset into the file to begin writing at */
- )
- {
- int rc; /* True if error has occured, else false */
- sqlite3_file pFile = id; /* File handle */
- Debug.Assert( amt > 0 );
- Debug.Assert( pFile != null );
- #if SQLITE_TEST
- if ( SimulateIOError() )
- return SQLITE_IOERR_WRITE;
- if ( SimulateDiskfullError() )
- return SQLITE_FULL;
- #endif
- #if SQLITE_DEBUG
- OSTRACE( "WRITE %d lock=%d\n", id.fs.GetHashCode(), id.locktype );
- #endif
- rc = seekWinFile( pFile, offset );
- //if( rc==0 ){
- // u8 *aRem = (u8 )pBuf; /* Data yet to be written */
- // int nRem = amt; /* Number of bytes yet to be written */
- // DWORD nWrite; /* Bytes written by each WriteFile() call */
- // while( nRem>0 && WriteFile(pFile->h, aRem, nRem, &nWrite, 0) && nWrite>0 ){
- // aRem += nWrite;
- // nRem -= nWrite;
- // }
- #if SQLITE_WINRT
- ulong wrote = id.fs.Position;
- #else
- long wrote = id.fs.Position;
- #endif
- try
- {
- Debug.Assert( pBuf.Length >= amt );
- #if SQLITE_WINRT
- using (IOutputStream outStream = id.fs.GetOutputStreamAt((ulong)offset))
- {
- outStream.WriteAsync(pBuf.AsBuffer(0, amt)).AsTask().Wait();
- outStream.FlushAsync().AsTask().Wait();
- wrote = (ulong)amt;
- }
- #else
- id.fs.Write( pBuf, 0, amt );
- wrote = id.fs.Position - wrote;
- #endif
- rc = 1;// Success
- }
- catch ( IOException e )
- {
- return SQLITE_READONLY;
- }
- if ( rc == 0 || amt > (int)wrote )
- {
- #if SQLITE_SILVERLIGHT || SQLITE_WINRT
- id.lastErrno = 1;
- #else
- id.lastErrno = (u32)Marshal.GetLastWin32Error();
- #endif
- if (( id.lastErrno == ERROR_HANDLE_DISK_FULL )
- || ( id.lastErrno == ERROR_DISK_FULL ))
- {
- return SQLITE_FULL;
- }
- else
- {
- return winLogError(SQLITE_IOERR_WRITE, "winWrite", pFile.zPath);
- }
- }
- return SQLITE_OK;
- }
- /*
- ** Truncate an open file to a specified size
- */
- static int winTruncate( sqlite3_file id, sqlite3_int64 nByte )
- {
- sqlite3_file pFile = id; /* File handle object */
- int rc = SQLITE_OK; /* Return code for this function */
- Debug.Assert( pFile != null );
- #if SQLITE_DEBUG
- #if WINDOWS_PHONE || SQLITE_SILVERLIGHT
- OSTRACE( "TRUNCATE %d %lld\n", id.fs.GetHashCode(), nByte );
- #else
- OSTRACE( "TRUNCATE %s %lld\n", id.fs.Name, nByte );
- #endif
- #endif
- #if SQLITE_TEST
- if ( SimulateIOError() )
- return SQLITE_IOERR_TRUNCATE;
- if ( SimulateIOError() )
- return SQLITE_IOERR_TRUNCATE;
- #endif
- /* If the user has configured a chunk-size for this file, truncate the
- ** file so that it consists of an integer number of chunks (i.e. the
- ** actual file size after the operation may be larger than the requested
- ** size).
- */
- if ( pFile.szChunk != 0 )
- {
- nByte = ( ( nByte + pFile.szChunk - 1 ) / pFile.szChunk ) * pFile.szChunk;
- }
- /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
- //if ( seekWinFile( pFile, nByte ) )
- //{
- // rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate1", pFile->zPath);
- //}
- //else if( 0==SetEndOfFile(pFile->h) ){
- // pFile->lastErrno = GetLastError();
- // rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate2", pFile->zPath);
- //}
- try
- {
- #if SQLITE_WINRT
- id.fs.Size = (ulong)nByte;
- #else
- id.fs.SetLength( nByte );
- #endif
- rc = SQLITE_OK;
- }
- catch ( IOException e )
- {
- #if SQLITE_SILVERLIGHT || SQLITE_WINRT
- id.lastErrno = 1;
- #else
- id.lastErrno = (u32)Marshal.GetLastWin32Error();
- #endif
- rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate2", pFile.zPath);
- }
- OSTRACE( "TRUNCATE %d %lld %s\n", id.fs.GetHashCode(), nByte, rc == SQLITE_OK ? "ok" : "failed" );
- return rc;
- }
- #if SQLITE_TEST
- /*
- ** Count the number of fullsyncs and normal syncs. This is used to test
- ** that syncs and fullsyncs are occuring at the right times.
- */
- #if !TCLSH
- static int sqlite3_sync_count = 0;
- static int sqlite3_fullsync_count = 0;
- #else
- static tcl.lang.Var.SQLITE3_GETSET sqlite3_sync_count = new tcl.lang.Var.SQLITE3_GETSET( "sqlite3_sync_count" );
- static tcl.lang.Var.SQLITE3_GETSET sqlite3_fullsync_count = new tcl.lang.Var.SQLITE3_GETSET( "sqlite_fullsync_count" );
- #endif
- #endif
- /*
- ** Make sure all writes to a particular file are committed to disk.
- */
- static int winSync( sqlite3_file id, int flags )
- {
- #if !(NDEBUG) || !(SQLITE_NO_SYNC) || (SQLITE_DEBUG)
- sqlite3_file pFile = (sqlite3_file)id;
- bool rc;
- #else
- UNUSED_PARAMETER(id);
- #endif
- Debug.Assert( pFile != null );
- /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */
- Debug.Assert( ( flags & 0x0F ) == SQLITE_SYNC_NORMAL
- || ( flags & 0x0F ) == SQLITE_SYNC_FULL
- );
- OSTRACE( "SYNC %d lock=%d\n", pFile.fs.GetHashCode(), pFile.locktype );
- /* Unix cannot, but some systems may return SQLITE_FULL from here. This
- ** line is to test that doing so does not cause any problems.
- */
- #if SQLITE_TEST
- if ( SimulateDiskfullError() )
- return SQLITE_FULL;
- #endif
- #if !SQLITE_TEST
- UNUSED_PARAMETER(flags);
- #else
- if ( (flags&0x0F)==SQLITE_SYNC_FULL )
- {
- #if !TCLSH
- sqlite3_fullsync_count++;
- }
- sqlite3_sync_count++;
- #else
- sqlite3_fullsync_count.iValue++;
- }
- sqlite3_sync_count.iValue++;
- #endif
- #endif
- /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
- ** no-op
- */
- #if SQLITE_NO_SYNC
- return SQLITE_OK;
- #else
- #if SQLITE_WINRT
- Stream stream = pFile.fs.AsStreamForWrite();
- stream.Flush();
- #else
- pFile.fs.Flush();
- #endif
- return SQLITE_OK;
- //rc = FlushFileBuffers(pFile->h);
- //SimulateIOError( rc=FALSE );
- //if( rc ){
- // return SQLITE_OK;
- //}else{
- // pFile->lastErrno = GetLastError();
- // return winLogError(SQLITE_IOERR_FSYNC, "winSync", pFile->zPath);
- //}
- #endif
- }
- /*
- ** Determine the current size of a file in bytes
- */
- static int winFileSize( sqlite3_file id, ref long pSize )
- {
- //DWORD upperBits;
- //DWORD lowerBits;
- // sqlite3_file pFile = (sqlite3_file)id;
- // DWORD error;
- Debug.Assert( id != null );
- #if SQLITE_TEST
- if ( SimulateIOError() )
- return SQLITE_IOERR_FSTAT;
- #endif
- //lowerBits = GetFileSize(pFile.fs.Name, upperBits);
- //if ( ( lowerBits == INVALID_FILE_SIZE )
- // && ( ( error = GetLastError() ) != NO_ERROR ) )
- //{
- // pFile.lastErrno = error;
- // return winLogError(SQLITE_IOERR_FSTAT, "winFileSize", pFile->zPath);
- //}
- //pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits;
- #if SQLITE_WINRT
- pSize = id.fs.CanRead ? (long)id.fs.Size : 0;
- #else
- pSize = id.fs.CanRead ? id.fs.Length : 0;
- #endif
- return SQLITE_OK;
- }
- /*
- ** Acquire a reader lock.
- ** Different API routines are called depending on whether or not this
- ** is Win95 or WinNT.
- */
- static int getReadLock( sqlite3_file pFile )
- {
- int res = 0;
- if ( isNT() )
- {
- res = lockingStrategy.SharedLockFile( pFile, SHARED_FIRST, SHARED_SIZE );
- }
- /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
- */
- #if !SQLITE_OS_WINCE
- //else
- //{
- // int lk;
- // sqlite3_randomness(lk.Length, lk);
- // pFile.sharedLockByte = (u16)((lk & 0x7fffffff)%(SHARED_SIZE - 1));
- // res = pFile.fs.Lock( SHARED_FIRST + pFile.sharedLockByte, 0, 1, 0);
- #endif
- //}
- if ( res == 0 )
- {
- #if SQLITE_SILVERLIGHT || SQLITE_WINRT
- pFile.lastErrno = 1;
- #else
- pFile.lastErrno = (u32)Marshal.GetLastWin32Error();
- #endif
- }
- /* No need to log a failure to lock */
- return res;
- }
- /*
- ** Undo a readlock
- */
- static int unlockReadLock( sqlite3_file pFile )
- {
- int res = 1;
- if ( isNT() )
- {
- try
- {
- lockingStrategy.UnlockFile( pFile, SHARED_FIRST, SHARED_SIZE ); // res = UnlockFile(pFile.h, SHARED_FIRST, 0, SHARED_SIZE, 0);
- }
- catch ( Exception e )
- {
- res = 0;
- }
- }
- /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
- */
- #if !SQLITE_OS_WINCE
- else
- {
- Debugger.Break(); // res = UnlockFile(pFile.h, SHARED_FIRST + pFilE.sharedLockByte, 0, 1, 0);
- }
- #endif
- if ( res == 0 )
- {
- #if SQLITE_SILVERLIGHT || SQLITE_WINRT
- pFile.lastErrno = 1;
- #else
- pFile.lastErrno = (u32)Marshal.GetLastWin32Error();
- #endif
- winLogError(SQLITE_IOERR_UNLOCK, "unlockReadLock", pFile.zPath);
- }
- return res;
- }
- /*
- ** Lock the file with the lock specified by parameter locktype - one
- ** of the following:
- **
- ** (1) SHARED_LOCK
- ** (2) RESERVED_LOCK
- ** (3) PENDING_LOCK
- ** (4) EXCLUSIVE_LOCK
- **
- ** Sometimes when requesting one lock state, additional lock states
- ** are inserted in between. The locking might fail on one of the later
- ** transitions leaving the lock state different from what it started but
- ** still short of its goal. The following chart shows the allowed
- ** transitions and the inserted intermediate states:
- **
- ** UNLOCKED . SHARED
- ** SHARED . RESERVED
- ** SHARED . (PENDING) . EXCLUSIVE
- ** RESERVED . (PENDING) . EXCLUSIVE
- ** PENDING . EXCLUSIVE
- **
- ** This routine will only increase a lock. The winUnlock() routine
- ** erases all locks at once and returns us immediately to locking level 0.
- ** It is not possible to lower the locking level one step at a time. You
- ** must go straight to locking level 0.
- */
- static int winLock( sqlite3_file id, int locktype )
- {
- int rc = SQLITE_OK; /* Return code from subroutines */
- int res = 1; /* Result of a windows lock call */
- int newLocktype; /* Set pFile.locktype to this value before exiting */
- bool gotPendingLock = false;/* True if we acquired a PENDING lock this time */
- sqlite3_file pFile = (sqlite3_file)id;
- DWORD error = NO_ERROR;
- Debug.Assert( id != null );
- #if SQLITE_DEBUG
- OSTRACE( "LOCK %d %d was %d(%d)\n",
- pFile.fs.GetHashCode(), locktype, pFile.locktype, pFile.sharedLockByte );
- #endif
- /* If there is already a lock of this type or more restrictive on the
- ** OsFile, do nothing. Don't use the end_lock: exit path, as
- ** sqlite3OsEnterMutex() hasn't been called yet.
- */
- if ( pFile.locktype >= locktype )
- {
- return SQLITE_OK;
- }
- /* Make sure the locking sequence is correct
- */
- Debug.Assert( pFile.locktype != NO_LOCK || locktype == SHARED_LOCK );
- Debug.Assert( locktype != PENDING_LOCK );
- Debug.Assert( locktype != RESERVED_LOCK || pFile.locktype == SHARED_LOCK );
- /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
- ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of
- ** the PENDING_LOCK byte is temporary.
- */
- newLocktype = pFile.locktype;
- if ( pFile.locktype == NO_LOCK
- || ( ( locktype == EXCLUSIVE_LOCK )
- && ( pFile.locktype == RESERVED_LOCK ) )
- )
- {
- int cnt = 3;
- res = 0;
- while ( cnt-- > 0 && res == 0 )//(res = LockFile(pFile.fs.SafeFileHandle.DangerousGetHandle().ToInt32(), PENDING_BYTE, 0, 1, 0)) == 0)
- {
- try
- {
- lockingStrategy.LockFile( pFile, PENDING_BYTE, 1 );
- res = 1;
- }
- catch ( Exception e )
- {
- /* Try 3 times to get the pending lock. The pending lock might be
- ** held by another reader process who will release it momentarily.
- */
- #if SQLITE_DEBUG
- OSTRACE( "could not get a PENDING lock. cnt=%d\n", cnt );
- #endif
- #if SQLITE_WINRT
- System.Threading.Tasks.Task.Delay(1).Wait();
- #else
- Thread.Sleep( 1 );
- #endif
- }
- }
- gotPendingLock = ( res != 0 );
- if ( 0 == res )
- {
- #if SQLITE_SILVERLIGHT || SQLITE_WINRT
- error = 1;
- #else
- error = (u32)Marshal.GetLastWin32Error();
- #endif
- }
- }
- /* Acquire a shared lock
- */
- if ( locktype == SHARED_LOCK && res != 0 )
- {
- Debug.Assert( pFile.locktype == NO_LOCK );
- res = getReadLock( pFile );
- if ( res != 0 )
- {
- newLocktype = SHARED_LOCK;
- }
- else
- {
- #if SQLITE_SILVERLIGHT || SQLITE_WINRT
- error = 1;
- #else
- error = (u32)Marshal.GetLastWin32Error();
- #endif
- }
- }
- /* Acquire a RESERVED lock
- */
- if ( ( locktype == RESERVED_LOCK ) && res != 0 )
- {
- Debug.Assert( pFile.locktype == SHARED_LOCK );
- try
- {
- lockingStrategy.LockFile( pFile, RESERVED_BYTE, 1 );//res = LockFile(pFile.fs.SafeFileHandle.DangerousGetHandle().ToInt32(), RESERVED_BYTE, 0, 1, 0);
- newLocktype = RESERVED_LOCK;
- res = 1;
- }
- catch ( Exception e )
- {
- res = 0;
- #if SQLITE_SILVERLIGHT || SQLITE_WINRT
- error = 1;
- #else
- error = (u32)Marshal.GetLastWin32Error();
- #endif
- }
- if ( res != 0 )
- {
- newLocktype = RESERVED_LOCK;
- }
- else
- {
- #if SQLITE_SILVERLIGHT
- error = 1;
- #else
- error = (u32)Marshal.GetLastWin32Error();
- #endif
- }
- }
- /* Acquire a PENDING lock
- */
- if ( locktype == EXCLUSIVE_LOCK && res != 0 )
- {
- newLocktype = PENDING_LOCK;
- gotPendingLock = false;
- }
- /* Acquire an EXCLUSIVE lock
- */
- if ( locktype == EXCLUSIVE_LOCK && res != 0 )
- {
- Debug.Assert( pFile.locktype >= SHARED_LOCK );
- res = unlockReadLock( pFile );
- #if SQLITE_DEBUG
- OSTRACE( "unreadlock = %d\n", res );
- #endif
- //res = LockFile(pFile.fs.SafeFileHandle.DangerousGetHandle().ToInt32(), SHARED_FIRST, 0, SHARED_SIZE, 0);
- try
- {
- lockingStrategy.LockFile( pFile, SHARED_FIRST, SHARED_SIZE );
- newLocktype = EXCLUSIVE_LOCK;
- res = 1;
- }
- catch ( Exception e )
- {
- res = 0;
- }
- if ( res != 0 )
- {
- newLocktype = EXCLUSIVE_LOCK;
- }
- else
- {
- #if SQLITE_SILVERLIGHT || SQLITE_WINRT
- error = 1;
- #else
- error = (u32)Marshal.GetLastWin32Error();
- #endif
- #if SQLITE_DEBUG
- OSTRACE( "error-code = %d\n", error );
- #endif
- getReadLock( pFile );
- }
- }
- /* If we are holding a PENDING lock that ought to be released, then
- ** release it now.
- */
- if ( gotPendingLock && locktype == SHARED_LOCK )
- {
- lockingStrategy.UnlockFile( pFile, PENDING_BYTE, 1 );
- }
- /* Update the state of the lock has held in the file descriptor then
- ** return the appropriate result code.
- */
- if ( res != 0 )
- {
- rc = SQLITE_OK;
- }
- else
- {
- #if SQLITE_DEBUG
- OSTRACE( "LOCK FAILED %d trying for %d but got %d\n", pFile.fs.GetHashCode(),
- locktype, newLocktype );
- #endif
- pFile.lastErrno = error;
- rc = SQLITE_BUSY;
- }
- pFile.locktype = (u8)newLocktype;
- return rc;
- }
- /*
- ** This routine checks if there is a RESERVED lock held on the specified
- ** file by this or any other process. If such a lock is held, return
- ** non-zero, otherwise zero.
- */
- static int winCheckReservedLock( sqlite3_file id, ref int pResOut )
- {
- int rc;
- sqlite3_file pFile = (sqlite3_file)id;
- if ( SimulateIOError() )
- return SQLITE_IOERR_CHECKRESERVEDLOCK;
- Debug.Assert( id != null );
- if ( pFile.locktype >= RESERVED_LOCK )
- {
- rc = 1;
- #if SQLITE_DEBUG
- #if WINDOWS_PHONE || SQLITE_SILVERLIGHT
- OSTRACE( "TEST WR-LOCK %d %d (local)\n", pFile.fs.GetHashCode(), rc );
- #else
- OSTRACE( "TEST WR-LOCK %s %d (local)\n", pFile.fs.Name, rc );
- #endif
- #endif
- }
- else
- {
- try
- {
- lockingStrategy.LockFile( pFile, RESERVED_BYTE, 1 );
- lockingStrategy.UnlockFile( pFile, RESERVED_BYTE, 1 );
- rc = 1;
- }
- catch ( IOException e )
- {
- rc = 0;
- }
- rc = 1 - rc; // !rc
- #if SQLITE_DEBUG
- OSTRACE( "TEST WR-LOCK %d %d (remote)\n", pFile.fs.GetHashCode(), rc );
- #endif
- }
- pResOut = rc;
- return SQLITE_OK;
- }
- /*
- ** Lower the locking level on file descriptor id to locktype. locktype
- ** must be either NO_LOCK or SHARED_LOCK.
- **
- ** If the locking level of the file descriptor is already at or below
- ** the requested locking level, this routine is a no-op.
- **
- ** It is not possible for this routine to fail if the second argument
- ** is NO_LOCK. If the second argument is SHARED_LOCK then this routine
- ** might return SQLITE_IOERR;
- */
- static int winUnlock( sqlite3_file id, int locktype )
- {
- int type;
- sqlite3_file pFile = (sqlite3_file)id;
- int rc = SQLITE_OK;
- Debug.Assert( pFile != null );
- Debug.Assert( locktype <= SHARED_LOCK );
- #if SQLITE_DEBUG
- OSTRACE( "UNLOCK %d to %d was %d(%d)\n", pFile.fs.GetHashCode(), locktype,
- pFile.locktype, pFile.sharedLockByte );
- #endif
- type = pFile.locktype;
- if ( type >= EXCLUSIVE_LOCK )
- {
- lockingStrategy.UnlockFile( pFile, SHARED_FIRST, SHARED_SIZE ); // UnlockFile(pFile.h, SHARED_FIRST, 0, SHARED_SIZE, 0);
- if ( locktype == SHARED_LOCK && getReadLock( pFile ) == 0 )
- {
- /* This should never happen. We should always be able to
- ** reacquire the read lock */
- rc = winLogError(SQLITE_IOERR_UNLOCK, "winUnlock", pFile.zPath);
- }
- }
- if ( type >= RESERVED_LOCK )
- {
- try
- {
- lockingStrategy.UnlockFile( pFile, RESERVED_BYTE, 1 );// UnlockFile(pFile.h, RESERVED_BYTE, 0, 1, 0);
- }
- catch ( Exception e )
- {
- }
- }
- if ( locktype == NO_LOCK && type >= SHARED_LOCK )
- {
- unlockReadLock( pFile );
- }
- if ( type >= PENDING_LOCK )
- {
- try
- {
- lockingStrategy.UnlockFile( pFile, PENDING_BYTE, 1 );// UnlockFile(pFile.h, PENDING_BYTE, 0, 1, 0);
- }
- catch ( Exception e )
- {
- }
- }
- pFile.locktype = (u8)locktype;
- return rc;
- }
- /*
- ** Control a…
Large files files are truncated, but you can click here to view the full file