PageRenderTime 65ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/Languages/IronPython/IronPython.SQLite/c#sqlite/os_win_c.cs

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