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