|
ds@1952
|
1 |
/* |
|
ds@1952
|
2 |
** 2004 May 22 |
|
ds@1952
|
3 |
** |
|
ds@1952
|
4 |
** The author disclaims copyright to this source code. In place of |
|
ds@1952
|
5 |
** a legal notice, here is a blessing: |
|
ds@1952
|
6 |
** |
|
ds@1952
|
7 |
** May you do good and not evil. |
|
ds@1952
|
8 |
** May you find forgiveness for yourself and forgive others. |
|
ds@1952
|
9 |
** May you share freely, never taking more than you give. |
|
ds@1952
|
10 |
** |
|
ds@1952
|
11 |
****************************************************************************** |
|
ds@1952
|
12 |
** |
|
ds@1952
|
13 |
** This file contains code that is specific to windows. |
|
ds@1952
|
14 |
*/ |
|
ds@1952
|
15 |
#include "sqliteInt.h" |
|
ds@1952
|
16 |
#if OS_WIN /* This file is used for windows only */ |
|
ds@1952
|
17 |
|
|
ds@1952
|
18 |
|
|
ds@1952
|
19 |
/* |
|
ds@1952
|
20 |
** A Note About Memory Allocation: |
|
ds@1952
|
21 |
** |
|
ds@1952
|
22 |
** This driver uses malloc()/free() directly rather than going through |
|
ds@1952
|
23 |
** the SQLite-wrappers sqlite3_malloc()/sqlite3_free(). Those wrappers |
|
ds@1952
|
24 |
** are designed for use on embedded systems where memory is scarce and |
|
ds@1952
|
25 |
** malloc failures happen frequently. Win32 does not typically run on |
|
ds@1952
|
26 |
** embedded systems, and when it does the developers normally have bigger |
|
ds@1952
|
27 |
** problems to worry about than running out of memory. So there is not |
|
ds@1952
|
28 |
** a compelling need to use the wrappers. |
|
ds@1952
|
29 |
** |
|
ds@1952
|
30 |
** But there is a good reason to not use the wrappers. If we use the |
|
ds@1952
|
31 |
** wrappers then we will get simulated malloc() failures within this |
|
ds@1952
|
32 |
** driver. And that causes all kinds of problems for our tests. We |
|
ds@1952
|
33 |
** could enhance SQLite to deal with simulated malloc failures within |
|
ds@1952
|
34 |
** the OS driver, but the code to deal with those failure would not |
|
ds@1952
|
35 |
** be exercised on Linux (which does not need to malloc() in the driver) |
|
ds@1952
|
36 |
** and so we would have difficulty writing coverage tests for that |
|
ds@1952
|
37 |
** code. Better to leave the code out, we think. |
|
ds@1952
|
38 |
** |
|
ds@1952
|
39 |
** The point of this discussion is as follows: When creating a new |
|
ds@1952
|
40 |
** OS layer for an embedded system, if you use this file as an example, |
|
ds@1952
|
41 |
** avoid the use of malloc()/free(). Those routines work ok on windows |
|
ds@1952
|
42 |
** desktops but not so well in embedded systems. |
|
ds@1952
|
43 |
*/ |
|
ds@1952
|
44 |
|
|
ds@1952
|
45 |
#include <winbase.h> |
|
ds@1952
|
46 |
|
|
ds@1952
|
47 |
#ifdef __CYGWIN__ |
|
ds@1952
|
48 |
# include <sys/cygwin.h> |
|
ds@1952
|
49 |
#endif |
|
ds@1952
|
50 |
|
|
ds@1952
|
51 |
/* |
|
ds@1952
|
52 |
** Macros used to determine whether or not to use threads. |
|
ds@1952
|
53 |
*/ |
|
ds@1952
|
54 |
#if defined(THREADSAFE) && THREADSAFE |
|
ds@1952
|
55 |
# define SQLITE_W32_THREADS 1 |
|
ds@1952
|
56 |
#endif |
|
ds@1952
|
57 |
|
|
ds@1952
|
58 |
/* |
|
ds@1952
|
59 |
** Include code that is common to all os_*.c files |
|
ds@1952
|
60 |
*/ |
|
ds@1952
|
61 |
#include "os_common.h" |
|
ds@1952
|
62 |
|
|
ds@1952
|
63 |
/* |
|
ds@1952
|
64 |
** Determine if we are dealing with WindowsCE - which has a much |
|
ds@1952
|
65 |
** reduced API. |
|
ds@1952
|
66 |
*/ |
|
ds@1952
|
67 |
#if defined(_WIN32_WCE) |
|
ds@1952
|
68 |
# define OS_WINCE 1 |
|
ds@1952
|
69 |
# define AreFileApisANSI() 1 |
|
ds@1952
|
70 |
#else |
|
ds@1952
|
71 |
# define OS_WINCE 0 |
|
ds@1952
|
72 |
#endif |
|
ds@1952
|
73 |
|
|
ds@1952
|
74 |
/* |
|
ds@1952
|
75 |
** WinCE lacks native support for file locking so we have to fake it |
|
ds@1952
|
76 |
** with some code of our own. |
|
ds@1952
|
77 |
*/ |
|
ds@1952
|
78 |
#if OS_WINCE |
|
ds@1952
|
79 |
typedef struct winceLock { |
|
ds@1952
|
80 |
int nReaders; /* Number of reader locks obtained */ |
|
ds@1952
|
81 |
BOOL bPending; /* Indicates a pending lock has been obtained */ |
|
ds@1952
|
82 |
BOOL bReserved; /* Indicates a reserved lock has been obtained */ |
|
ds@1952
|
83 |
BOOL bExclusive; /* Indicates an exclusive lock has been obtained */ |
|
ds@1952
|
84 |
} winceLock; |
|
ds@1952
|
85 |
#endif |
|
ds@1952
|
86 |
|
|
ds@1952
|
87 |
/* |
|
ds@1952
|
88 |
** The winFile structure is a subclass of sqlite3_file* specific to the win32 |
|
ds@1952
|
89 |
** portability layer. |
|
ds@1952
|
90 |
*/ |
|
ds@1952
|
91 |
typedef struct winFile winFile; |
|
ds@1952
|
92 |
struct winFile { |
|
ds@1952
|
93 |
const sqlite3_io_methods *pMethod;/* Must be first */ |
|
ds@1952
|
94 |
HANDLE h; /* Handle for accessing the file */ |
|
ds@1952
|
95 |
unsigned char locktype; /* Type of lock currently held on this file */ |
|
ds@1952
|
96 |
short sharedLockByte; /* Randomly chosen byte used as a shared lock */ |
|
ds@1952
|
97 |
#if OS_WINCE |
|
ds@1952
|
98 |
WCHAR *zDeleteOnClose; /* Name of file to delete when closing */ |
|
ds@1952
|
99 |
HANDLE hMutex; /* Mutex used to control access to shared lock */ |
|
ds@1952
|
100 |
HANDLE hShared; /* Shared memory segment used for locking */ |
|
ds@1952
|
101 |
winceLock local; /* Locks obtained by this instance of winFile */ |
|
ds@1952
|
102 |
winceLock *shared; /* Global shared lock memory for the file */ |
|
ds@1952
|
103 |
#endif |
|
ds@1952
|
104 |
}; |
|
ds@1952
|
105 |
|
|
ds@1952
|
106 |
|
|
ds@1952
|
107 |
/* |
|
ds@1952
|
108 |
** The following variable is (normally) set once and never changes |
|
ds@1952
|
109 |
** thereafter. It records whether the operating system is Win95 |
|
ds@1952
|
110 |
** or WinNT. |
|
ds@1952
|
111 |
** |
|
ds@1952
|
112 |
** 0: Operating system unknown. |
|
ds@1952
|
113 |
** 1: Operating system is Win95. |
|
ds@1952
|
114 |
** 2: Operating system is WinNT. |
|
ds@1952
|
115 |
** |
|
ds@1952
|
116 |
** In order to facilitate testing on a WinNT system, the test fixture |
|
ds@1952
|
117 |
** can manually set this value to 1 to emulate Win98 behavior. |
|
ds@1952
|
118 |
*/ |
|
ds@1952
|
119 |
#ifdef SQLITE_TEST |
|
ds@1952
|
120 |
int sqlite3_os_type = 0; |
|
ds@1952
|
121 |
#else |
|
ds@1952
|
122 |
static int sqlite3_os_type = 0; |
|
ds@1952
|
123 |
#endif |
|
ds@1952
|
124 |
|
|
ds@1952
|
125 |
/* |
|
ds@1952
|
126 |
** Return true (non-zero) if we are running under WinNT, Win2K, WinXP, |
|
ds@1952
|
127 |
** or WinCE. Return false (zero) for Win95, Win98, or WinME. |
|
ds@1952
|
128 |
** |
|
ds@1952
|
129 |
** Here is an interesting observation: Win95, Win98, and WinME lack |
|
ds@1952
|
130 |
** the LockFileEx() API. But we can still statically link against that |
|
ds@1952
|
131 |
** API as long as we don't call it win running Win95/98/ME. A call to |
|
ds@1952
|
132 |
** this routine is used to determine if the host is Win95/98/ME or |
|
ds@1952
|
133 |
** WinNT/2K/XP so that we will know whether or not we can safely call |
|
ds@1952
|
134 |
** the LockFileEx() API. |
|
ds@1952
|
135 |
*/ |
|
ds@1952
|
136 |
#if OS_WINCE |
|
ds@1952
|
137 |
# define isNT() (1) |
|
ds@1952
|
138 |
#else |
|
ds@1952
|
139 |
static int isNT(void){ |
|
ds@1952
|
140 |
if( sqlite3_os_type==0 ){ |
|
ds@1952
|
141 |
OSVERSIONINFO sInfo; |
|
ds@1952
|
142 |
sInfo.dwOSVersionInfoSize = sizeof(sInfo); |
|
ds@1952
|
143 |
GetVersionEx(&sInfo); |
|
ds@1952
|
144 |
sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; |
|
ds@1952
|
145 |
} |
|
ds@1952
|
146 |
return sqlite3_os_type==2; |
|
ds@1952
|
147 |
} |
|
ds@1952
|
148 |
#endif /* OS_WINCE */ |
|
ds@1952
|
149 |
|
|
ds@1952
|
150 |
/* |
|
ds@1952
|
151 |
** Convert a UTF-8 string to microsoft unicode (UTF-16?). |
|
ds@1952
|
152 |
** |
|
ds@1952
|
153 |
** Space to hold the returned string is obtained from malloc. |
|
ds@1952
|
154 |
*/ |
|
ds@1952
|
155 |
static WCHAR *utf8ToUnicode(const char *zFilename){ |
|
ds@1952
|
156 |
int nChar; |
|
ds@1952
|
157 |
WCHAR *zWideFilename; |
|
ds@1952
|
158 |
|
|
ds@1952
|
159 |
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0); |
|
ds@1952
|
160 |
zWideFilename = malloc( nChar*sizeof(zWideFilename[0]) ); |
|
ds@1952
|
161 |
if( zWideFilename==0 ){ |
|
ds@1952
|
162 |
return 0; |
|
ds@1952
|
163 |
} |
|
ds@1952
|
164 |
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar); |
|
ds@1952
|
165 |
if( nChar==0 ){ |
|
ds@1952
|
166 |
free(zWideFilename); |
|
ds@1952
|
167 |
zWideFilename = 0; |
|
ds@1952
|
168 |
} |
|
ds@1952
|
169 |
return zWideFilename; |
|
ds@1952
|
170 |
} |
|
ds@1952
|
171 |
|
|
ds@1952
|
172 |
/* |
|
ds@1952
|
173 |
** Convert microsoft unicode to UTF-8. Space to hold the returned string is |
|
ds@1952
|
174 |
** obtained from malloc(). |
|
ds@1952
|
175 |
*/ |
|
ds@1952
|
176 |
static char *unicodeToUtf8(const WCHAR *zWideFilename){ |
|
ds@1952
|
177 |
int nByte; |
|
ds@1952
|
178 |
char *zFilename; |
|
ds@1952
|
179 |
|
|
ds@1952
|
180 |
nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0); |
|
ds@1952
|
181 |
zFilename = malloc( nByte ); |
|
ds@1952
|
182 |
if( zFilename==0 ){ |
|
ds@1952
|
183 |
return 0; |
|
ds@1952
|
184 |
} |
|
ds@1952
|
185 |
nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte, |
|
ds@1952
|
186 |
0, 0); |
|
ds@1952
|
187 |
if( nByte == 0 ){ |
|
ds@1952
|
188 |
free(zFilename); |
|
ds@1952
|
189 |
zFilename = 0; |
|
ds@1952
|
190 |
} |
|
ds@1952
|
191 |
return zFilename; |
|
ds@1952
|
192 |
} |
|
ds@1952
|
193 |
|
|
ds@1952
|
194 |
/* |
|
ds@1952
|
195 |
** Convert an ansi string to microsoft unicode, based on the |
|
ds@1952
|
196 |
** current codepage settings for file apis. |
|
ds@1952
|
197 |
** |
|
ds@1952
|
198 |
** Space to hold the returned string is obtained |
|
ds@1952
|
199 |
** from malloc. |
|
ds@1952
|
200 |
*/ |
|
ds@1952
|
201 |
static WCHAR *mbcsToUnicode(const char *zFilename){ |
|
ds@1952
|
202 |
int nByte; |
|
ds@1952
|
203 |
WCHAR *zMbcsFilename; |
|
ds@1952
|
204 |
int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; |
|
ds@1952
|
205 |
|
|
ds@1952
|
206 |
nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, NULL,0)*sizeof(WCHAR); |
|
ds@1952
|
207 |
zMbcsFilename = malloc( nByte*sizeof(zMbcsFilename[0]) ); |
|
ds@1952
|
208 |
if( zMbcsFilename==0 ){ |
|
ds@1952
|
209 |
return 0; |
|
ds@1952
|
210 |
} |
|
ds@1952
|
211 |
nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename, nByte); |
|
ds@1952
|
212 |
if( nByte==0 ){ |
|
ds@1952
|
213 |
free(zMbcsFilename); |
|
ds@1952
|
214 |
zMbcsFilename = 0; |
|
ds@1952
|
215 |
} |
|
ds@1952
|
216 |
return zMbcsFilename; |
|
ds@1952
|
217 |
} |
|
ds@1952
|
218 |
|
|
ds@1952
|
219 |
/* |
|
ds@1952
|
220 |
** Convert microsoft unicode to multibyte character string, based on the |
|
ds@1952
|
221 |
** user's Ansi codepage. |
|
ds@1952
|
222 |
** |
|
ds@1952
|
223 |
** Space to hold the returned string is obtained from |
|
ds@1952
|
224 |
** malloc(). |
|
ds@1952
|
225 |
*/ |
|
ds@1952
|
226 |
static char *unicodeToMbcs(const WCHAR *zWideFilename){ |
|
ds@1952
|
227 |
int nByte; |
|
ds@1952
|
228 |
char *zFilename; |
|
ds@1952
|
229 |
int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; |
|
ds@1952
|
230 |
|
|
ds@1952
|
231 |
nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0); |
|
ds@1952
|
232 |
zFilename = malloc( nByte ); |
|
ds@1952
|
233 |
if( zFilename==0 ){ |
|
ds@1952
|
234 |
return 0; |
|
ds@1952
|
235 |
} |
|
ds@1952
|
236 |
nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename, nByte, |
|
ds@1952
|
237 |
0, 0); |
|
ds@1952
|
238 |
if( nByte == 0 ){ |
|
ds@1952
|
239 |
free(zFilename); |
|
ds@1952
|
240 |
zFilename = 0; |
|
ds@1952
|
241 |
} |
|
ds@1952
|
242 |
return zFilename; |
|
ds@1952
|
243 |
} |
|
ds@1952
|
244 |
|
|
ds@1952
|
245 |
/* |
|
ds@1952
|
246 |
** Convert multibyte character string to UTF-8. Space to hold the |
|
ds@1952
|
247 |
** returned string is obtained from malloc(). |
|
ds@1952
|
248 |
*/ |
|
ds@1952
|
249 |
static char *mbcsToUtf8(const char *zFilename){ |
|
ds@1952
|
250 |
char *zFilenameUtf8; |
|
ds@1952
|
251 |
WCHAR *zTmpWide; |
|
ds@1952
|
252 |
|
|
ds@1952
|
253 |
zTmpWide = mbcsToUnicode(zFilename); |
|
ds@1952
|
254 |
if( zTmpWide==0 ){ |
|
ds@1952
|
255 |
return 0; |
|
ds@1952
|
256 |
} |
|
ds@1952
|
257 |
zFilenameUtf8 = unicodeToUtf8(zTmpWide); |
|
ds@1952
|
258 |
free(zTmpWide); |
|
ds@1952
|
259 |
return zFilenameUtf8; |
|
ds@1952
|
260 |
} |
|
ds@1952
|
261 |
|
|
ds@1952
|
262 |
/* |
|
ds@1952
|
263 |
** Convert UTF-8 to multibyte character string. Space to hold the |
|
ds@1952
|
264 |
** returned string is obtained from malloc(). |
|
ds@1952
|
265 |
*/ |
|
ds@1952
|
266 |
static char *utf8ToMbcs(const char *zFilename){ |
|
ds@1952
|
267 |
char *zFilenameMbcs; |
|
ds@1952
|
268 |
WCHAR *zTmpWide; |
|
ds@1952
|
269 |
|
|
ds@1952
|
270 |
zTmpWide = utf8ToUnicode(zFilename); |
|
ds@1952
|
271 |
if( zTmpWide==0 ){ |
|
ds@1952
|
272 |
return 0; |
|
ds@1952
|
273 |
} |
|
ds@1952
|
274 |
zFilenameMbcs = unicodeToMbcs(zTmpWide); |
|
ds@1952
|
275 |
free(zTmpWide); |
|
ds@1952
|
276 |
return zFilenameMbcs; |
|
ds@1952
|
277 |
} |
|
ds@1952
|
278 |
|
|
ds@1952
|
279 |
#if OS_WINCE |
|
ds@1952
|
280 |
/************************************************************************* |
|
ds@1952
|
281 |
** This section contains code for WinCE only. |
|
ds@1952
|
282 |
*/ |
|
ds@1952
|
283 |
/* |
|
ds@1952
|
284 |
** WindowsCE does not have a localtime() function. So create a |
|
ds@1952
|
285 |
** substitute. |
|
ds@1952
|
286 |
*/ |
|
ds@1952
|
287 |
#include <time.h> |
|
ds@1952
|
288 |
struct tm *__cdecl localtime(const time_t *t) |
|
ds@1952
|
289 |
{ |
|
ds@1952
|
290 |
static struct tm y; |
|
ds@1952
|
291 |
FILETIME uTm, lTm; |
|
ds@1952
|
292 |
SYSTEMTIME pTm; |
|
ds@1952
|
293 |
sqlite3_int64 t64; |
|
ds@1952
|
294 |
t64 = *t; |
|
ds@1952
|
295 |
t64 = (t64 + 11644473600)*10000000; |
|
ds@1952
|
296 |
uTm.dwLowDateTime = t64 & 0xFFFFFFFF; |
|
ds@1952
|
297 |
uTm.dwHighDateTime= t64 >> 32; |
|
ds@1952
|
298 |
FileTimeToLocalFileTime(&uTm,&lTm); |
|
ds@1952
|
299 |
FileTimeToSystemTime(&lTm,&pTm); |
|
ds@1952
|
300 |
y.tm_year = pTm.wYear - 1900; |
|
ds@1952
|
301 |
y.tm_mon = pTm.wMonth - 1; |
|
ds@1952
|
302 |
y.tm_wday = pTm.wDayOfWeek; |
|
ds@1952
|
303 |
y.tm_mday = pTm.wDay; |
|
ds@1952
|
304 |
y.tm_hour = pTm.wHour; |
|
ds@1952
|
305 |
y.tm_min = pTm.wMinute; |
|
ds@1952
|
306 |
y.tm_sec = pTm.wSecond; |
|
ds@1952
|
307 |
return &y; |
|
ds@1952
|
308 |
} |
|
ds@1952
|
309 |
|
|
ds@1952
|
310 |
/* This will never be called, but defined to make the code compile */ |
|
ds@1952
|
311 |
#define GetTempPathA(a,b) |
|
ds@1952
|
312 |
|
|
ds@1952
|
313 |
#define LockFile(a,b,c,d,e) winceLockFile(&a, b, c, d, e) |
|
ds@1952
|
314 |
#define UnlockFile(a,b,c,d,e) winceUnlockFile(&a, b, c, d, e) |
|
ds@1952
|
315 |
#define LockFileEx(a,b,c,d,e,f) winceLockFileEx(&a, b, c, d, e, f) |
|
ds@1952
|
316 |
|
|
ds@1952
|
317 |
#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-offsetof(winFile,h)] |
|
ds@1952
|
318 |
|
|
ds@1952
|
319 |
/* |
|
ds@1952
|
320 |
** Acquire a lock on the handle h |
|
ds@1952
|
321 |
*/ |
|
ds@1952
|
322 |
static void winceMutexAcquire(HANDLE h){ |
|
ds@1952
|
323 |
DWORD dwErr; |
|
ds@1952
|
324 |
do { |
|
ds@1952
|
325 |
dwErr = WaitForSingleObject(h, INFINITE); |
|
ds@1952
|
326 |
} while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED); |
|
ds@1952
|
327 |
} |
|
ds@1952
|
328 |
/* |
|
ds@1952
|
329 |
** Release a lock acquired by winceMutexAcquire() |
|
ds@1952
|
330 |
*/ |
|
ds@1952
|
331 |
#define winceMutexRelease(h) ReleaseMutex(h) |
|
ds@1952
|
332 |
|
|
ds@1952
|
333 |
/* |
|
ds@1952
|
334 |
** Create the mutex and shared memory used for locking in the file |
|
ds@1952
|
335 |
** descriptor pFile |
|
ds@1952
|
336 |
*/ |
|
ds@1952
|
337 |
static BOOL winceCreateLock(const char *zFilename, winFile *pFile){ |
|
ds@1952
|
338 |
WCHAR *zTok; |
|
ds@1952
|
339 |
WCHAR *zName = utf8ToUnicode(zFilename); |
|
ds@1952
|
340 |
BOOL bInit = TRUE; |
|
ds@1952
|
341 |
|
|
ds@1952
|
342 |
/* Initialize the local lockdata */ |
|
ds@1952
|
343 |
ZeroMemory(&pFile->local, sizeof(pFile->local)); |
|
ds@1952
|
344 |
|
|
ds@1952
|
345 |
/* Replace the backslashes from the filename and lowercase it |
|
ds@1952
|
346 |
** to derive a mutex name. */ |
|
ds@1952
|
347 |
zTok = CharLowerW(zName); |
|
ds@1952
|
348 |
for (;*zTok;zTok++){ |
|
ds@1952
|
349 |
if (*zTok == '\\') *zTok = '_'; |
|
ds@1952
|
350 |
} |
|
ds@1952
|
351 |
|
|
ds@1952
|
352 |
/* Create/open the named mutex */ |
|
ds@1952
|
353 |
pFile->hMutex = CreateMutexW(NULL, FALSE, zName); |
|
ds@1952
|
354 |
if (!pFile->hMutex){ |
|
ds@1952
|
355 |
free(zName); |
|
ds@1952
|
356 |
return FALSE; |
|
ds@1952
|
357 |
} |
|
ds@1952
|
358 |
|
|
ds@1952
|
359 |
/* Acquire the mutex before continuing */ |
|
ds@1952
|
360 |
winceMutexAcquire(pFile->hMutex); |
|
ds@1952
|
361 |
|
|
ds@1952
|
362 |
/* Since the names of named mutexes, semaphores, file mappings etc are |
|
ds@1952
|
363 |
** case-sensitive, take advantage of that by uppercasing the mutex name |
|
ds@1952
|
364 |
** and using that as the shared filemapping name. |
|
ds@1952
|
365 |
*/ |
|
ds@1952
|
366 |
CharUpperW(zName); |
|
ds@1952
|
367 |
pFile->hShared = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, |
|
ds@1952
|
368 |
PAGE_READWRITE, 0, sizeof(winceLock), |
|
ds@1952
|
369 |
zName); |
|
ds@1952
|
370 |
|
|
ds@1952
|
371 |
/* Set a flag that indicates we're the first to create the memory so it |
|
ds@1952
|
372 |
** must be zero-initialized */ |
|
ds@1952
|
373 |
if (GetLastError() == ERROR_ALREADY_EXISTS){ |
|
ds@1952
|
374 |
bInit = FALSE; |
|
ds@1952
|
375 |
} |
|
ds@1952
|
376 |
|
|
ds@1952
|
377 |
free(zName); |
|
ds@1952
|
378 |
|
|
ds@1952
|
379 |
/* If we succeeded in making the shared memory handle, map it. */ |
|
ds@1952
|
380 |
if (pFile->hShared){ |
|
ds@1952
|
381 |
pFile->shared = (winceLock*)MapViewOfFile(pFile->hShared, |
|
ds@1952
|
382 |
FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock)); |
|
ds@1952
|
383 |
/* If mapping failed, close the shared memory handle and erase it */ |
|
ds@1952
|
384 |
if (!pFile->shared){ |
|
ds@1952
|
385 |
CloseHandle(pFile->hShared); |
|
ds@1952
|
386 |
pFile->hShared = NULL; |
|
ds@1952
|
387 |
} |
|
ds@1952
|
388 |
} |
|
ds@1952
|
389 |
|
|
ds@1952
|
390 |
/* If shared memory could not be created, then close the mutex and fail */ |
|
ds@1952
|
391 |
if (pFile->hShared == NULL){ |
|
ds@1952
|
392 |
winceMutexRelease(pFile->hMutex); |
|
ds@1952
|
393 |
CloseHandle(pFile->hMutex); |
|
ds@1952
|
394 |
pFile->hMutex = NULL; |
|
ds@1952
|
395 |
return FALSE; |
|
ds@1952
|
396 |
} |
|
ds@1952
|
397 |
|
|
ds@1952
|
398 |
/* Initialize the shared memory if we're supposed to */ |
|
ds@1952
|
399 |
if (bInit) { |
|
ds@1952
|
400 |
ZeroMemory(pFile->shared, sizeof(winceLock)); |
|
ds@1952
|
401 |
} |
|
ds@1952
|
402 |
|
|
ds@1952
|
403 |
winceMutexRelease(pFile->hMutex); |
|
ds@1952
|
404 |
return TRUE; |
|
ds@1952
|
405 |
} |
|
ds@1952
|
406 |
|
|
ds@1952
|
407 |
/* |
|
ds@1952
|
408 |
** Destroy the part of winFile that deals with wince locks |
|
ds@1952
|
409 |
*/ |
|
ds@1952
|
410 |
static void winceDestroyLock(winFile *pFile){ |
|
ds@1952
|
411 |
if (pFile->hMutex){ |
|
ds@1952
|
412 |
/* Acquire the mutex */ |
|
ds@1952
|
413 |
winceMutexAcquire(pFile->hMutex); |
|
ds@1952
|
414 |
|
|
ds@1952
|
415 |
/* The following blocks should probably assert in debug mode, but they |
|
ds@1952
|
416 |
are to cleanup in case any locks remained open */ |
|
ds@1952
|
417 |
if (pFile->local.nReaders){ |
|
ds@1952
|
418 |
pFile->shared->nReaders --; |
|
ds@1952
|
419 |
} |
|
ds@1952
|
420 |
if (pFile->local.bReserved){ |
|
ds@1952
|
421 |
pFile->shared->bReserved = FALSE; |
|
ds@1952
|
422 |
} |
|
ds@1952
|
423 |
if (pFile->local.bPending){ |
|
ds@1952
|
424 |
pFile->shared->bPending = FALSE; |
|
ds@1952
|
425 |
} |
|
ds@1952
|
426 |
if (pFile->local.bExclusive){ |
|
ds@1952
|
427 |
pFile->shared->bExclusive = FALSE; |
|
ds@1952
|
428 |
} |
|
ds@1952
|
429 |
|
|
ds@1952
|
430 |
/* De-reference and close our copy of the shared memory handle */ |
|
ds@1952
|
431 |
UnmapViewOfFile(pFile->shared); |
|
ds@1952
|
432 |
CloseHandle(pFile->hShared); |
|
ds@1952
|
433 |
|
|
ds@1952
|
434 |
if( pFile->zDeleteOnClose ){ |
|
ds@1952
|
435 |
DeleteFileW(pFile->zDeleteOnClose); |
|
ds@1952
|
436 |
free(pFile->zDeleteOnClose); |
|
ds@1952
|
437 |
pFile->zDeleteOnClose = 0; |
|
ds@1952
|
438 |
} |
|
ds@1952
|
439 |
|
|
ds@1952
|
440 |
/* Done with the mutex */ |
|
ds@1952
|
441 |
winceMutexRelease(pFile->hMutex); |
|
ds@1952
|
442 |
CloseHandle(pFile->hMutex); |
|
ds@1952
|
443 |
pFile->hMutex = NULL; |
|
ds@1952
|
444 |
} |
|
ds@1952
|
445 |
} |
|
ds@1952
|
446 |
|
|
ds@1952
|
447 |
/* |
|
ds@1952
|
448 |
** An implementation of the LockFile() API of windows for wince |
|
ds@1952
|
449 |
*/ |
|
ds@1952
|
450 |
static BOOL winceLockFile( |
|
ds@1952
|
451 |
HANDLE *phFile, |
|
ds@1952
|
452 |
DWORD dwFileOffsetLow, |
|
ds@1952
|
453 |
DWORD dwFileOffsetHigh, |
|
ds@1952
|
454 |
DWORD nNumberOfBytesToLockLow, |
|
ds@1952
|
455 |
DWORD nNumberOfBytesToLockHigh |
|
ds@1952
|
456 |
){ |
|
ds@1952
|
457 |
winFile *pFile = HANDLE_TO_WINFILE(phFile); |
|
ds@1952
|
458 |
BOOL bReturn = FALSE; |
|
ds@1952
|
459 |
|
|
ds@1952
|
460 |
if (!pFile->hMutex) return TRUE; |
|
ds@1952
|
461 |
winceMutexAcquire(pFile->hMutex); |
|
ds@1952
|
462 |
|
|
ds@1952
|
463 |
/* Wanting an exclusive lock? */ |
|
ds@1952
|
464 |
if (dwFileOffsetLow == SHARED_FIRST |
|
ds@1952
|
465 |
&& nNumberOfBytesToLockLow == SHARED_SIZE){ |
|
ds@1952
|
466 |
if (pFile->shared->nReaders == 0 && pFile->shared->bExclusive == 0){ |
|
ds@1952
|
467 |
pFile->shared->bExclusive = TRUE; |
|
ds@1952
|
468 |
pFile->local.bExclusive = TRUE; |
|
ds@1952
|
469 |
bReturn = TRUE; |
|
ds@1952
|
470 |
} |
|
ds@1952
|
471 |
} |
|
ds@1952
|
472 |
|
|
ds@1952
|
473 |
/* Want a read-only lock? */ |
|
ds@1952
|
474 |
else if ((dwFileOffsetLow >= SHARED_FIRST && |
|
ds@1952
|
475 |
dwFileOffsetLow < SHARED_FIRST + SHARED_SIZE) && |
|
ds@1952
|
476 |
nNumberOfBytesToLockLow == 1){ |
|
ds@1952
|
477 |
if (pFile->shared->bExclusive == 0){ |
|
ds@1952
|
478 |
pFile->local.nReaders ++; |
|
ds@1952
|
479 |
if (pFile->local.nReaders == 1){ |
|
ds@1952
|
480 |
pFile->shared->nReaders ++; |
|
ds@1952
|
481 |
} |
|
ds@1952
|
482 |
bReturn = TRUE; |
|
ds@1952
|
483 |
} |
|
ds@1952
|
484 |
} |
|
ds@1952
|
485 |
|
|
ds@1952
|
486 |
/* Want a pending lock? */ |
|
ds@1952
|
487 |
else if (dwFileOffsetLow == PENDING_BYTE && nNumberOfBytesToLockLow == 1){ |
|
ds@1952
|
488 |
/* If no pending lock has been acquired, then acquire it */ |
|
ds@1952
|
489 |
if (pFile->shared->bPending == 0) { |
|
ds@1952
|
490 |
pFile->shared->bPending = TRUE; |
|
ds@1952
|
491 |
pFile->local.bPending = TRUE; |
|
ds@1952
|
492 |
bReturn = TRUE; |
|
ds@1952
|
493 |
} |
|
ds@1952
|
494 |
} |
|
ds@1952
|
495 |
/* Want a reserved lock? */ |
|
ds@1952
|
496 |
else if (dwFileOffsetLow == RESERVED_BYTE && nNumberOfBytesToLockLow == 1){ |
|
ds@1952
|
497 |
if (pFile->shared->bReserved == 0) { |
|
ds@1952
|
498 |
pFile->shared->bReserved = TRUE; |
|
ds@1952
|
499 |
pFile->local.bReserved = TRUE; |
|
ds@1952
|
500 |
bReturn = TRUE; |
|
ds@1952
|
501 |
} |
|
ds@1952
|
502 |
} |
|
ds@1952
|
503 |
|
|
ds@1952
|
504 |
winceMutexRelease(pFile->hMutex); |
|
ds@1952
|
505 |
return bReturn; |
|
ds@1952
|
506 |
} |
|
ds@1952
|
507 |
|
|
ds@1952
|
508 |
/* |
|
ds@1952
|
509 |
** An implementation of the UnlockFile API of windows for wince |
|
ds@1952
|
510 |
*/ |
|
ds@1952
|
511 |
static BOOL winceUnlockFile( |
|
ds@1952
|
512 |
HANDLE *phFile, |
|
ds@1952
|
513 |
DWORD dwFileOffsetLow, |
|
ds@1952
|
514 |
DWORD dwFileOffsetHigh, |
|
ds@1952
|
515 |
DWORD nNumberOfBytesToUnlockLow, |
|
ds@1952
|
516 |
DWORD nNumberOfBytesToUnlockHigh |
|
ds@1952
|
517 |
){ |
|
ds@1952
|
518 |
winFile *pFile = HANDLE_TO_WINFILE(phFile); |
|
ds@1952
|
519 |
BOOL bReturn = FALSE; |
|
ds@1952
|
520 |
|
|
ds@1952
|
521 |
if (!pFile->hMutex) return TRUE; |
|
ds@1952
|
522 |
winceMutexAcquire(pFile->hMutex); |
|
ds@1952
|
523 |
|
|
ds@1952
|
524 |
/* Releasing a reader lock or an exclusive lock */ |
|
ds@1952
|
525 |
if (dwFileOffsetLow >= SHARED_FIRST && |
|
ds@1952
|
526 |
dwFileOffsetLow < SHARED_FIRST + SHARED_SIZE){ |
|
ds@1952
|
527 |
/* Did we have an exclusive lock? */ |
|
ds@1952
|
528 |
if (pFile->local.bExclusive){ |
|
ds@1952
|
529 |
pFile->local.bExclusive = FALSE; |
|
ds@1952
|
530 |
pFile->shared->bExclusive = FALSE; |
|
ds@1952
|
531 |
bReturn = TRUE; |
|
ds@1952
|
532 |
} |
|
ds@1952
|
533 |
|
|
ds@1952
|
534 |
/* Did we just have a reader lock? */ |
|
ds@1952
|
535 |
else if (pFile->local.nReaders){ |
|
ds@1952
|
536 |
pFile->local.nReaders --; |
|
ds@1952
|
537 |
if (pFile->local.nReaders == 0) |
|
ds@1952
|
538 |
{ |
|
ds@1952
|
539 |
pFile->shared->nReaders --; |
|
ds@1952
|
540 |
} |
|
ds@1952
|
541 |
bReturn = TRUE; |
|
ds@1952
|
542 |
} |
|
ds@1952
|
543 |
} |
|
ds@1952
|
544 |
|
|
ds@1952
|
545 |
/* Releasing a pending lock */ |
|
ds@1952
|
546 |
else if (dwFileOffsetLow == PENDING_BYTE && nNumberOfBytesToUnlockLow == 1){ |
|
ds@1952
|
547 |
if (pFile->local.bPending){ |
|
ds@1952
|
548 |
pFile->local.bPending = FALSE; |
|
ds@1952
|
549 |
pFile->shared->bPending = FALSE; |
|
ds@1952
|
550 |
bReturn = TRUE; |
|
ds@1952
|
551 |
} |
|
ds@1952
|
552 |
} |
|
ds@1952
|
553 |
/* Releasing a reserved lock */ |
|
ds@1952
|
554 |
else if (dwFileOffsetLow == RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1){ |
|
ds@1952
|
555 |
if (pFile->local.bReserved) { |
|
ds@1952
|
556 |
pFile->local.bReserved = FALSE; |
|
ds@1952
|
557 |
pFile->shared->bReserved = FALSE; |
|
ds@1952
|
558 |
bReturn = TRUE; |
|
ds@1952
|
559 |
} |
|
ds@1952
|
560 |
} |
|
ds@1952
|
561 |
|
|
ds@1952
|
562 |
winceMutexRelease(pFile->hMutex); |
|
ds@1952
|
563 |
return bReturn; |
|
ds@1952
|
564 |
} |
|
ds@1952
|
565 |
|
|
ds@1952
|
566 |
/* |
|
ds@1952
|
567 |
** An implementation of the LockFileEx() API of windows for wince |
|
ds@1952
|
568 |
*/ |
|
ds@1952
|
569 |
static BOOL winceLockFileEx( |
|
ds@1952
|
570 |
HANDLE *phFile, |
|
ds@1952
|
571 |
DWORD dwFlags, |
|
ds@1952
|
572 |
DWORD dwReserved, |
|
ds@1952
|
573 |
DWORD nNumberOfBytesToLockLow, |
|
ds@1952
|
574 |
DWORD nNumberOfBytesToLockHigh, |
|
ds@1952
|
575 |
LPOVERLAPPED lpOverlapped |
|
ds@1952
|
576 |
){ |
|
ds@1952
|
577 |
/* If the caller wants a shared read lock, forward this call |
|
ds@1952
|
578 |
** to winceLockFile */ |
|
ds@1952
|
579 |
if (lpOverlapped->Offset == SHARED_FIRST && |
|
ds@1952
|
580 |
dwFlags == 1 && |
|
ds@1952
|
581 |
nNumberOfBytesToLockLow == SHARED_SIZE){ |
|
ds@1952
|
582 |
return winceLockFile(phFile, SHARED_FIRST, 0, 1, 0); |
|
ds@1952
|
583 |
} |
|
ds@1952
|
584 |
return FALSE; |
|
ds@1952
|
585 |
} |
|
ds@1952
|
586 |
/* |
|
ds@1952
|
587 |
** End of the special code for wince |
|
ds@1952
|
588 |
*****************************************************************************/ |
|
ds@1952
|
589 |
#endif /* OS_WINCE */ |
|
ds@1952
|
590 |
|
|
ds@1952
|
591 |
/***************************************************************************** |
|
ds@1952
|
592 |
** The next group of routines implement the I/O methods specified |
|
ds@1952
|
593 |
** by the sqlite3_io_methods object. |
|
ds@1952
|
594 |
******************************************************************************/ |
|
ds@1952
|
595 |
|
|
ds@1952
|
596 |
/* |
|
ds@1952
|
597 |
** Close a file. |
|
ds@1952
|
598 |
** |
|
ds@1952
|
599 |
** It is reported that an attempt to close a handle might sometimes |
|
ds@1952
|
600 |
** fail. This is a very unreasonable result, but windows is notorious |
|
ds@1952
|
601 |
** for being unreasonable so I do not doubt that it might happen. If |
|
ds@1952
|
602 |
** the close fails, we pause for 100 milliseconds and try again. As |
|
ds@1952
|
603 |
** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before |
|
ds@1952
|
604 |
** giving up and returning an error. |
|
ds@1952
|
605 |
*/ |
|
ds@1952
|
606 |
#define MX_CLOSE_ATTEMPT 3 |
|
ds@1952
|
607 |
static int winClose(sqlite3_file *id){ |
|
ds@1952
|
608 |
int rc, cnt = 0; |
|
ds@1952
|
609 |
winFile *pFile = (winFile*)id; |
|
ds@1952
|
610 |
OSTRACE2("CLOSE %d\n", pFile->h); |
|
ds@1952
|
611 |
do{ |
|
ds@1952
|
612 |
rc = CloseHandle(pFile->h); |
|
ds@1952
|
613 |
}while( rc==0 && cnt++ < MX_CLOSE_ATTEMPT && (Sleep(100), 1) ); |
|
ds@1952
|
614 |
#if OS_WINCE |
|
ds@1952
|
615 |
winceDestroyLock(pFile); |
|
ds@1952
|
616 |
#endif |
|
ds@1952
|
617 |
OpenCounter(-1); |
|
ds@1952
|
618 |
return rc ? SQLITE_OK : SQLITE_IOERR; |
|
ds@1952
|
619 |
} |
|
ds@1952
|
620 |
|
|
ds@1952
|
621 |
/* |
|
ds@1952
|
622 |
** Some microsoft compilers lack this definition. |
|
ds@1952
|
623 |
*/ |
|
ds@1952
|
624 |
#ifndef INVALID_SET_FILE_POINTER |
|
ds@1952
|
625 |
# define INVALID_SET_FILE_POINTER ((DWORD)-1) |
|
ds@1952
|
626 |
#endif |
|
ds@1952
|
627 |
|
|
ds@1952
|
628 |
/* |
|
ds@1952
|
629 |
** Read data from a file into a buffer. Return SQLITE_OK if all |
|
ds@1952
|
630 |
** bytes were read successfully and SQLITE_IOERR if anything goes |
|
ds@1952
|
631 |
** wrong. |
|
ds@1952
|
632 |
*/ |
|
ds@1952
|
633 |
static int winRead( |
|
ds@1952
|
634 |
sqlite3_file *id, /* File to read from */ |
|
ds@1952
|
635 |
void *pBuf, /* Write content into this buffer */ |
|
ds@1952
|
636 |
int amt, /* Number of bytes to read */ |
|
ds@1952
|
637 |
sqlite3_int64 offset /* Begin reading at this offset */ |
|
ds@1952
|
638 |
){ |
|
ds@1952
|
639 |
LONG upperBits = (offset>>32) & 0x7fffffff; |
|
ds@1952
|
640 |
LONG lowerBits = offset & 0xffffffff; |
|
ds@1952
|
641 |
DWORD rc; |
|
ds@1952
|
642 |
DWORD got; |
|
ds@1952
|
643 |
winFile *pFile = (winFile*)id; |
|
ds@1952
|
644 |
assert( id!=0 ); |
|
ds@1952
|
645 |
SimulateIOError(return SQLITE_IOERR_READ); |
|
ds@1952
|
646 |
OSTRACE3("READ %d lock=%d\n", pFile->h, pFile->locktype); |
|
ds@1952
|
647 |
rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); |
|
ds@1952
|
648 |
if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){ |
|
ds@1952
|
649 |
return SQLITE_FULL; |
|
ds@1952
|
650 |
} |
|
ds@1952
|
651 |
if( !ReadFile(pFile->h, pBuf, amt, &got, 0) ){ |
|
ds@1952
|
652 |
return SQLITE_IOERR_READ; |
|
ds@1952
|
653 |
} |
|
ds@1952
|
654 |
if( got==(DWORD)amt ){ |
|
ds@1952
|
655 |
return SQLITE_OK; |
|
ds@1952
|
656 |
}else{ |
|
ds@1952
|
657 |
memset(&((char*)pBuf)[got], 0, amt-got); |
|
ds@1952
|
658 |
return SQLITE_IOERR_SHORT_READ; |
|
ds@1952
|
659 |
} |
|
ds@1952
|
660 |
} |
|
ds@1952
|
661 |
|
|
ds@1952
|
662 |
/* |
|
ds@1952
|
663 |
** Write data from a buffer into a file. Return SQLITE_OK on success |
|
ds@1952
|
664 |
** or some other error code on failure. |
|
ds@1952
|
665 |
*/ |
|
ds@1952
|
666 |
static int winWrite( |
|
ds@1952
|
667 |
sqlite3_file *id, /* File to write into */ |
|
ds@1952
|
668 |
const void *pBuf, /* The bytes to be written */ |
|
ds@1952
|
669 |
int amt, /* Number of bytes to write */ |
|
ds@1952
|
670 |
sqlite3_int64 offset /* Offset into the file to begin writing at */ |
|
ds@1952
|
671 |
){ |
|
ds@1952
|
672 |
LONG upperBits = (offset>>32) & 0x7fffffff; |
|
ds@1952
|
673 |
LONG lowerBits = offset & 0xffffffff; |
|
ds@1952
|
674 |
DWORD rc; |
|
ds@1952
|
675 |
DWORD wrote; |
|
ds@1952
|
676 |
winFile *pFile = (winFile*)id; |
|
ds@1952
|
677 |
assert( id!=0 ); |
|
ds@1952
|
678 |
SimulateIOError(return SQLITE_IOERR_WRITE); |
|
ds@1952
|
679 |
SimulateDiskfullError(return SQLITE_FULL); |
|
ds@1952
|
680 |
OSTRACE3("WRITE %d lock=%d\n", pFile->h, pFile->locktype); |
|
ds@1952
|
681 |
rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); |
|
ds@1952
|
682 |
if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){ |
|
ds@1952
|
683 |
return SQLITE_FULL; |
|
ds@1952
|
684 |
} |
|
ds@1952
|
685 |
assert( amt>0 ); |
|
ds@1952
|
686 |
while( |
|
ds@1952
|
687 |
amt>0 |
|
ds@1952
|
688 |
&& (rc = WriteFile(pFile->h, pBuf, amt, &wrote, 0))!=0 |
|
ds@1952
|
689 |
&& wrote>0 |
|
ds@1952
|
690 |
){ |
|
ds@1952
|
691 |
amt -= wrote; |
|
ds@1952
|
692 |
pBuf = &((char*)pBuf)[wrote]; |
|
ds@1952
|
693 |
} |
|
ds@1952
|
694 |
if( !rc || amt>(int)wrote ){ |
|
ds@1952
|
695 |
return SQLITE_FULL; |
|
ds@1952
|
696 |
} |
|
ds@1952
|
697 |
return SQLITE_OK; |
|
ds@1952
|
698 |
} |
|
ds@1952
|
699 |
|
|
ds@1952
|
700 |
/* |
|
ds@1952
|
701 |
** Truncate an open file to a specified size |
|
ds@1952
|
702 |
*/ |
|
ds@1952
|
703 |
static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ |
|
ds@1952
|
704 |
LONG upperBits = (nByte>>32) & 0x7fffffff; |
|
ds@1952
|
705 |
LONG lowerBits = nByte & 0xffffffff; |
|
ds@1952
|
706 |
winFile *pFile = (winFile*)id; |
|
ds@1952
|
707 |
OSTRACE3("TRUNCATE %d %lld\n", pFile->h, nByte); |
|
ds@1952
|
708 |
SimulateIOError(return SQLITE_IOERR_TRUNCATE); |
|
ds@1952
|
709 |
SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); |
|
ds@1952
|
710 |
SetEndOfFile(pFile->h); |
|
ds@1952
|
711 |
return SQLITE_OK; |
|
ds@1952
|
712 |
} |
|
ds@1952
|
713 |
|
|
ds@1952
|
714 |
#ifdef SQLITE_TEST |
|
ds@1952
|
715 |
/* |
|
ds@1952
|
716 |
** Count the number of fullsyncs and normal syncs. This is used to test |
|
ds@1952
|
717 |
** that syncs and fullsyncs are occuring at the right times. |
|
ds@1952
|
718 |
*/ |
|
ds@1952
|
719 |
int sqlite3_sync_count = 0; |
|
ds@1952
|
720 |
int sqlite3_fullsync_count = 0; |
|
ds@1952
|
721 |
#endif |
|
ds@1952
|
722 |
|
|
ds@1952
|
723 |
/* |
|
ds@1952
|
724 |
** Make sure all writes to a particular file are committed to disk. |
|
ds@1952
|
725 |
*/ |
|
ds@1952
|
726 |
static int winSync(sqlite3_file *id, int flags){ |
|
ds@1952
|
727 |
winFile *pFile = (winFile*)id; |
|
ds@1952
|
728 |
OSTRACE3("SYNC %d lock=%d\n", pFile->h, pFile->locktype); |
|
ds@1952
|
729 |
#ifdef SQLITE_TEST |
|
ds@1952
|
730 |
if( flags & SQLITE_SYNC_FULL ){ |
|
ds@1952
|
731 |
sqlite3_fullsync_count++; |
|
ds@1952
|
732 |
} |
|
ds@1952
|
733 |
sqlite3_sync_count++; |
|
ds@1952
|
734 |
#endif |
|
ds@1952
|
735 |
if( FlushFileBuffers(pFile->h) ){ |
|
ds@1952
|
736 |
return SQLITE_OK; |
|
ds@1952
|
737 |
}else{ |
|
ds@1952
|
738 |
return SQLITE_IOERR; |
|
ds@1952
|
739 |
} |
|
ds@1952
|
740 |
} |
|
ds@1952
|
741 |
|
|
ds@1952
|
742 |
/* |
|
ds@1952
|
743 |
** Determine the current size of a file in bytes |
|
ds@1952
|
744 |
*/ |
|
ds@1952
|
745 |
static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ |
|
ds@1952
|
746 |
winFile *pFile = (winFile*)id; |
|
ds@1952
|
747 |
DWORD upperBits, lowerBits; |
|
ds@1952
|
748 |
SimulateIOError(return SQLITE_IOERR_FSTAT); |
|
ds@1952
|
749 |
lowerBits = GetFileSize(pFile->h, &upperBits); |
|
ds@1952
|
750 |
*pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits; |
|
ds@1952
|
751 |
return SQLITE_OK; |
|
ds@1952
|
752 |
} |
|
ds@1952
|
753 |
|
|
ds@1952
|
754 |
/* |
|
ds@1952
|
755 |
** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems. |
|
ds@1952
|
756 |
*/ |
|
ds@1952
|
757 |
#ifndef LOCKFILE_FAIL_IMMEDIATELY |
|
ds@1952
|
758 |
# define LOCKFILE_FAIL_IMMEDIATELY 1 |
|
ds@1952
|
759 |
#endif |
|
ds@1952
|
760 |
|
|
ds@1952
|
761 |
/* |
|
ds@1952
|
762 |
** Acquire a reader lock. |
|
ds@1952
|
763 |
** Different API routines are called depending on whether or not this |
|
ds@1952
|
764 |
** is Win95 or WinNT. |
|
ds@1952
|
765 |
*/ |
|
ds@1952
|
766 |
static int getReadLock(winFile *pFile){ |
|
ds@1952
|
767 |
int res; |
|
ds@1952
|
768 |
if( isNT() ){ |
|
ds@1952
|
769 |
OVERLAPPED ovlp; |
|
ds@1952
|
770 |
ovlp.Offset = SHARED_FIRST; |
|
ds@1952
|
771 |
ovlp.OffsetHigh = 0; |
|
ds@1952
|
772 |
ovlp.hEvent = 0; |
|
ds@1952
|
773 |
res = LockFileEx(pFile->h, LOCKFILE_FAIL_IMMEDIATELY, |
|
ds@1952
|
774 |
0, SHARED_SIZE, 0, &ovlp); |
|
ds@1952
|
775 |
}else{ |
|
ds@1952
|
776 |
int lk; |
|
ds@1952
|
777 |
sqlite3Randomness(sizeof(lk), &lk); |
|
ds@1952
|
778 |
pFile->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1); |
|
ds@1952
|
779 |
res = LockFile(pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); |
|
ds@1952
|
780 |
} |
|
ds@1952
|
781 |
return res; |
|
ds@1952
|
782 |
} |
|
ds@1952
|
783 |
|
|
ds@1952
|
784 |
/* |
|
ds@1952
|
785 |
** Undo a readlock |
|
ds@1952
|
786 |
*/ |
|
ds@1952
|
787 |
static int unlockReadLock(winFile *pFile){ |
|
ds@1952
|
788 |
int res; |
|
ds@1952
|
789 |
if( isNT() ){ |
|
ds@1952
|
790 |
res = UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); |
|
ds@1952
|
791 |
}else{ |
|
ds@1952
|
792 |
res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0); |
|
ds@1952
|
793 |
} |
|
ds@1952
|
794 |
return res; |
|
ds@1952
|
795 |
} |
|
ds@1952
|
796 |
|
|
ds@1952
|
797 |
/* |
|
ds@1952
|
798 |
** Lock the file with the lock specified by parameter locktype - one |
|
ds@1952
|
799 |
** of the following: |
|
ds@1952
|
800 |
** |
|
ds@1952
|
801 |
** (1) SHARED_LOCK |
|
ds@1952
|
802 |
** (2) RESERVED_LOCK |
|
ds@1952
|
803 |
** (3) PENDING_LOCK |
|
ds@1952
|
804 |
** (4) EXCLUSIVE_LOCK |
|
ds@1952
|
805 |
** |
|
ds@1952
|
806 |
** Sometimes when requesting one lock state, additional lock states |
|
ds@1952
|
807 |
** are inserted in between. The locking might fail on one of the later |
|
ds@1952
|
808 |
** transitions leaving the lock state different from what it started but |
|
ds@1952
|
809 |
** still short of its goal. The following chart shows the allowed |
|
ds@1952
|
810 |
** transitions and the inserted intermediate states: |
|
ds@1952
|
811 |
** |
|
ds@1952
|
812 |
** UNLOCKED -> SHARED |
|
ds@1952
|
813 |
** SHARED -> RESERVED |
|
ds@1952
|
814 |
** SHARED -> (PENDING) -> EXCLUSIVE |
|
ds@1952
|
815 |
** RESERVED -> (PENDING) -> EXCLUSIVE |
|
ds@1952
|
816 |
** PENDING -> EXCLUSIVE |
|
ds@1952
|
817 |
** |
|
ds@1952
|
818 |
** This routine will only increase a lock. The winUnlock() routine |
|
ds@1952
|
819 |
** erases all locks at once and returns us immediately to locking level 0. |
|
ds@1952
|
820 |
** It is not possible to lower the locking level one step at a time. You |
|
ds@1952
|
821 |
** must go straight to locking level 0. |
|
ds@1952
|
822 |
*/ |
|
ds@1952
|
823 |
static int winLock(sqlite3_file *id, int locktype){ |
|
ds@1952
|
824 |
int rc = SQLITE_OK; /* Return code from subroutines */ |
|
ds@1952
|
825 |
int res = 1; /* Result of a windows lock call */ |
|
ds@1952
|
826 |
int newLocktype; /* Set pFile->locktype to this value before exiting */ |
|
ds@1952
|
827 |
int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ |
|
ds@1952
|
828 |
winFile *pFile = (winFile*)id; |
|
ds@1952
|
829 |
|
|
ds@1952
|
830 |
assert( pFile!=0 ); |
|
ds@1952
|
831 |
OSTRACE5("LOCK %d %d was %d(%d)\n", |
|
ds@1952
|
832 |
pFile->h, locktype, pFile->locktype, pFile->sharedLockByte); |
|
ds@1952
|
833 |
|
|
ds@1952
|
834 |
/* If there is already a lock of this type or more restrictive on the |
|
ds@1952
|
835 |
** OsFile, do nothing. Don't use the end_lock: exit path, as |
|
ds@1952
|
836 |
** sqlite3OsEnterMutex() hasn't been called yet. |
|
ds@1952
|
837 |
*/ |
|
ds@1952
|
838 |
if( pFile->locktype>=locktype ){ |
|
ds@1952
|
839 |
return SQLITE_OK; |
|
ds@1952
|
840 |
} |
|
ds@1952
|
841 |
|
|
ds@1952
|
842 |
/* Make sure the locking sequence is correct |
|
ds@1952
|
843 |
*/ |
|
ds@1952
|
844 |
assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); |
|
ds@1952
|
845 |
assert( locktype!=PENDING_LOCK ); |
|
ds@1952
|
846 |
assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); |
|
ds@1952
|
847 |
|
|
ds@1952
|
848 |
/* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or |
|
ds@1952
|
849 |
** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of |
|
ds@1952
|
850 |
** the PENDING_LOCK byte is temporary. |
|
ds@1952
|
851 |
*/ |
|
ds@1952
|
852 |
newLocktype = pFile->locktype; |
|
ds@1952
|
853 |
if( pFile->locktype==NO_LOCK |
|
ds@1952
|
854 |
|| (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK) |
|
ds@1952
|
855 |
){ |
|
ds@1952
|
856 |
int cnt = 3; |
|
ds@1952
|
857 |
while( cnt-->0 && (res = LockFile(pFile->h, PENDING_BYTE, 0, 1, 0))==0 ){ |
|
ds@1952
|
858 |
/* Try 3 times to get the pending lock. The pending lock might be |
|
ds@1952
|
859 |
** held by another reader process who will release it momentarily. |
|
ds@1952
|
860 |
*/ |
|
ds@1952
|
861 |
OSTRACE2("could not get a PENDING lock. cnt=%d\n", cnt); |
|
ds@1952
|
862 |
Sleep(1); |
|
ds@1952
|
863 |
} |
|
ds@1952
|
864 |
gotPendingLock = res; |
|
ds@1952
|
865 |
} |
|
ds@1952
|
866 |
|
|
ds@1952
|
867 |
/* Acquire a shared lock |
|
ds@1952
|
868 |
*/ |
|
ds@1952
|
869 |
if( locktype==SHARED_LOCK && res ){ |
|
ds@1952
|
870 |
assert( pFile->locktype==NO_LOCK ); |
|
ds@1952
|
871 |
res = getReadLock(pFile); |
|
ds@1952
|
872 |
if( res ){ |
|
ds@1952
|
873 |
newLocktype = SHARED_LOCK; |
|
ds@1952
|
874 |
} |
|
ds@1952
|
875 |
} |
|
ds@1952
|
876 |
|
|
ds@1952
|
877 |
/* Acquire a RESERVED lock |
|
ds@1952
|
878 |
*/ |
|
ds@1952
|
879 |
if( locktype==RESERVED_LOCK && res ){ |
|
ds@1952
|
880 |
assert( pFile->locktype==SHARED_LOCK ); |
|
ds@1952
|
881 |
res = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); |
|
ds@1952
|
882 |
if( res ){ |
|
ds@1952
|
883 |
newLocktype = RESERVED_LOCK; |
|
ds@1952
|
884 |
} |
|
ds@1952
|
885 |
} |
|
ds@1952
|
886 |
|
|
ds@1952
|
887 |
/* Acquire a PENDING lock |
|
ds@1952
|
888 |
*/ |
|
ds@1952
|
889 |
if( locktype==EXCLUSIVE_LOCK && res ){ |
|
ds@1952
|
890 |
newLocktype = PENDING_LOCK; |
|
ds@1952
|
891 |
gotPendingLock = 0; |
|
ds@1952
|
892 |
} |
|
ds@1952
|
893 |
|
|
ds@1952
|
894 |
/* Acquire an EXCLUSIVE lock |
|
ds@1952
|
895 |
*/ |
|
ds@1952
|
896 |
if( locktype==EXCLUSIVE_LOCK && res ){ |
|
ds@1952
|
897 |
assert( pFile->locktype>=SHARED_LOCK ); |
|
ds@1952
|
898 |
res = unlockReadLock(pFile); |
|
ds@1952
|
899 |
OSTRACE2("unreadlock = %d\n", res); |
|
ds@1952
|
900 |
res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); |
|
ds@1952
|
901 |
if( res ){ |
|
ds@1952
|
902 |
newLocktype = EXCLUSIVE_LOCK; |
|
ds@1952
|
903 |
}else{ |
|
ds@1952
|
904 |
OSTRACE2("error-code = %d\n", GetLastError()); |
|
ds@1952
|
905 |
getReadLock(pFile); |
|
ds@1952
|
906 |
} |
|
ds@1952
|
907 |
} |
|
ds@1952
|
908 |
|
|
ds@1952
|
909 |
/* If we are holding a PENDING lock that ought to be released, then |
|
ds@1952
|
910 |
** release it now. |
|
ds@1952
|
911 |
*/ |
|
ds@1952
|
912 |
if( gotPendingLock && locktype==SHARED_LOCK ){ |
|
ds@1952
|
913 |
UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0); |
|
ds@1952
|
914 |
} |
|
ds@1952
|
915 |
|
|
ds@1952
|
916 |
/* Update the state of the lock has held in the file descriptor then |
|
ds@1952
|
917 |
** return the appropriate result code. |
|
ds@1952
|
918 |
*/ |
|
ds@1952
|
919 |
if( res ){ |
|
ds@1952
|
920 |
rc = SQLITE_OK; |
|
ds@1952
|
921 |
}else{ |
|
ds@1952
|
922 |
OSTRACE4("LOCK FAILED %d trying for %d but got %d\n", pFile->h, |
|
ds@1952
|
923 |
locktype, newLocktype); |
|
ds@1952
|
924 |
rc = SQLITE_BUSY; |
|
ds@1952
|
925 |
} |
|
ds@1952
|
926 |
pFile->locktype = newLocktype; |
|
ds@1952
|
927 |
return rc; |
|
ds@1952
|
928 |
} |
|
ds@1952
|
929 |
|
|
ds@1952
|
930 |
/* |
|
ds@1952
|
931 |
** This routine checks if there is a RESERVED lock held on the specified |
|
ds@1952
|
932 |
** file by this or any other process. If such a lock is held, return |
|
ds@1952
|
933 |
** non-zero, otherwise zero. |
|
ds@1952
|
934 |
*/ |
|
ds@1952
|
935 |
static int winCheckReservedLock(sqlite3_file *id){ |
|
ds@1952
|
936 |
int rc; |
|
ds@1952
|
937 |
winFile *pFile = (winFile*)id; |
|
ds@1952
|
938 |
assert( pFile!=0 ); |
|
ds@1952
|
939 |
if( pFile->locktype>=RESERVED_LOCK ){ |
|
ds@1952
|
940 |
rc = 1; |
|
ds@1952
|
941 |
OSTRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc); |
|
ds@1952
|
942 |
}else{ |
|
ds@1952
|
943 |
rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); |
|
ds@1952
|
944 |
if( rc ){ |
|
ds@1952
|
945 |
UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); |
|
ds@1952
|
946 |
} |
|
ds@1952
|
947 |
rc = !rc; |
|
ds@1952
|
948 |
OSTRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc); |
|
ds@1952
|
949 |
} |
|
ds@1952
|
950 |
return rc; |
|
ds@1952
|
951 |
} |
|
ds@1952
|
952 |
|
|
ds@1952
|
953 |
/* |
|
ds@1952
|
954 |
** Lower the locking level on file descriptor id to locktype. locktype |
|
ds@1952
|
955 |
** must be either NO_LOCK or SHARED_LOCK. |
|
ds@1952
|
956 |
** |
|
ds@1952
|
957 |
** If the locking level of the file descriptor is already at or below |
|
ds@1952
|
958 |
** the requested locking level, this routine is a no-op. |
|
ds@1952
|
959 |
** |
|
ds@1952
|
960 |
** It is not possible for this routine to fail if the second argument |
|
ds@1952
|
961 |
** is NO_LOCK. If the second argument is SHARED_LOCK then this routine |
|
ds@1952
|
962 |
** might return SQLITE_IOERR; |
|
ds@1952
|
963 |
*/ |
|
ds@1952
|
964 |
static int winUnlock(sqlite3_file *id, int locktype){ |
|
ds@1952
|
965 |
int type; |
|
ds@1952
|
966 |
winFile *pFile = (winFile*)id; |
|
ds@1952
|
967 |
int rc = SQLITE_OK; |
|
ds@1952
|
968 |
assert( pFile!=0 ); |
|
ds@1952
|
969 |
assert( locktype<=SHARED_LOCK ); |
|
ds@1952
|
970 |
OSTRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype, |
|
ds@1952
|
971 |
pFile->locktype, pFile->sharedLockByte); |
|
ds@1952
|
972 |
type = pFile->locktype; |
|
ds@1952
|
973 |
if( type>=EXCLUSIVE_LOCK ){ |
|
ds@1952
|
974 |
UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); |
|
ds@1952
|
975 |
if( locktype==SHARED_LOCK && !getReadLock(pFile) ){ |
|
ds@1952
|
976 |
/* This should never happen. We should always be able to |
|
ds@1952
|
977 |
** reacquire the read lock */ |
|
ds@1952
|
978 |
rc = SQLITE_IOERR_UNLOCK; |
|
ds@1952
|
979 |
} |
|
ds@1952
|
980 |
} |
|
ds@1952
|
981 |
if( type>=RESERVED_LOCK ){ |
|
ds@1952
|
982 |
UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); |
|
ds@1952
|
983 |
} |
|
ds@1952
|
984 |
if( locktype==NO_LOCK && type>=SHARED_LOCK ){ |
|
ds@1952
|
985 |
unlockReadLock(pFile); |
|
ds@1952
|
986 |
} |
|
ds@1952
|
987 |
if( type>=PENDING_LOCK ){ |
|
ds@1952
|
988 |
UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0); |
|
ds@1952
|
989 |
} |
|
ds@1952
|
990 |
pFile->locktype = locktype; |
|
ds@1952
|
991 |
return rc; |
|
ds@1952
|
992 |
} |
|
ds@1952
|
993 |
|
|
ds@1952
|
994 |
/* |
|
ds@1952
|
995 |
** Control and query of the open file handle. |
|
ds@1952
|
996 |
*/ |
|
ds@1952
|
997 |
static int winFileControl(sqlite3_file *id, int op, void *pArg){ |
|
ds@1952
|
998 |
switch( op ){ |
|
ds@1952
|
999 |
case SQLITE_FCNTL_LOCKSTATE: { |
|
ds@1952
|
1000 |
*(int*)pArg = ((winFile*)id)->locktype; |
|
ds@1952
|
1001 |
return SQLITE_OK; |
|
ds@1952
|
1002 |
} |
|
ds@1952
|
1003 |
} |
|
ds@1952
|
1004 |
return SQLITE_ERROR; |
|
ds@1952
|
1005 |
} |
|
ds@1952
|
1006 |
|
|
ds@1952
|
1007 |
/* |
|
ds@1952
|
1008 |
** Return the sector size in bytes of the underlying block device for |
|
ds@1952
|
1009 |
** the specified file. This is almost always 512 bytes, but may be |
|
ds@1952
|
1010 |
** larger for some devices. |
|
ds@1952
|
1011 |
** |
|
ds@1952
|
1012 |
** SQLite code assumes this function cannot fail. It also assumes that |
|
ds@1952
|
1013 |
** if two files are created in the same file-system directory (i.e. |
|
ds@1952
|
1014 |
** a database and it's journal file) that the sector size will be the |
|
ds@1952
|
1015 |
** same for both. |
|
ds@1952
|
1016 |
*/ |
|
ds@1952
|
1017 |
static int winSectorSize(sqlite3_file *id){ |
|
ds@1952
|
1018 |
return SQLITE_DEFAULT_SECTOR_SIZE; |
|
ds@1952
|
1019 |
} |
|
ds@1952
|
1020 |
|
|
ds@1952
|
1021 |
/* |
|
ds@1952
|
1022 |
** Return a vector of device characteristics. |
|
ds@1952
|
1023 |
*/ |
|
ds@1952
|
1024 |
static int winDeviceCharacteristics(sqlite3_file *id){ |
|
ds@1952
|
1025 |
return 0; |
|
ds@1952
|
1026 |
} |
|
ds@1952
|
1027 |
|
|
ds@1952
|
1028 |
/* |
|
ds@1952
|
1029 |
** This vector defines all the methods that can operate on an |
|
ds@1952
|
1030 |
** sqlite3_file for win32. |
|
ds@1952
|
1031 |
*/ |
|
ds@1952
|
1032 |
static const sqlite3_io_methods winIoMethod = { |
|
ds@1952
|
1033 |
1, /* iVersion */ |
|
ds@1952
|
1034 |
winClose, |
|
ds@1952
|
1035 |
winRead, |
|
ds@1952
|
1036 |
winWrite, |
|
ds@1952
|
1037 |
winTruncate, |
|
ds@1952
|
1038 |
winSync, |
|
ds@1952
|
1039 |
winFileSize, |
|
ds@1952
|
1040 |
winLock, |
|
ds@1952
|
1041 |
winUnlock, |
|
ds@1952
|
1042 |
winCheckReservedLock, |
|
ds@1952
|
1043 |
winFileControl, |
|
ds@1952
|
1044 |
winSectorSize, |
|
ds@1952
|
1045 |
winDeviceCharacteristics |
|
ds@1952
|
1046 |
}; |
|
ds@1952
|
1047 |
|
|
ds@1952
|
1048 |
/*************************************************************************** |
|
ds@1952
|
1049 |
** Here ends the I/O methods that form the sqlite3_io_methods object. |
|
ds@1952
|
1050 |
** |
|
ds@1952
|
1051 |
** The next block of code implements the VFS methods. |
|
ds@1952
|
1052 |
****************************************************************************/ |
|
ds@1952
|
1053 |
|
|
ds@1952
|
1054 |
/* |
|
ds@1952
|
1055 |
** Convert a UTF-8 filename into whatever form the underlying |
|
ds@1952
|
1056 |
** operating system wants filenames in. Space to hold the result |
|
ds@1952
|
1057 |
** is obtained from malloc and must be freed by the calling |
|
ds@1952
|
1058 |
** function. |
|
ds@1952
|
1059 |
*/ |
|
ds@1952
|
1060 |
static void *convertUtf8Filename(const char *zFilename){ |
|
ds@1952
|
1061 |
void *zConverted = 0; |
|
ds@1952
|
1062 |
if( isNT() ){ |
|
ds@1952
|
1063 |
zConverted = utf8ToUnicode(zFilename); |
|
ds@1952
|
1064 |
}else{ |
|
ds@1952
|
1065 |
zConverted = utf8ToMbcs(zFilename); |
|
ds@1952
|
1066 |
} |
|
ds@1952
|
1067 |
/* caller will handle out of memory */ |
|
ds@1952
|
1068 |
return zConverted; |
|
ds@1952
|
1069 |
} |
|
ds@1952
|
1070 |
|
|
ds@1952
|
1071 |
/* |
|
ds@1952
|
1072 |
** Open a file. |
|
ds@1952
|
1073 |
*/ |
|
ds@1952
|
1074 |
static int winOpen( |
|
ds@1952
|
1075 |
sqlite3_vfs *pVfs, /* Not used */ |
|
ds@1952
|
1076 |
const char *zName, /* Name of the file (UTF-8) */ |
|
ds@1952
|
1077 |
sqlite3_file *id, /* Write the SQLite file handle here */ |
|
ds@1952
|
1078 |
int flags, /* Open mode flags */ |
|
ds@1952
|
1079 |
int *pOutFlags /* Status return flags */ |
|
ds@1952
|
1080 |
){ |
|
ds@1952
|
1081 |
HANDLE h; |
|
ds@1952
|
1082 |
DWORD dwDesiredAccess; |
|
ds@1952
|
1083 |
DWORD dwShareMode; |
|
ds@1952
|
1084 |
DWORD dwCreationDisposition; |
|
ds@1952
|
1085 |
DWORD dwFlagsAndAttributes = 0; |
|
ds@1952
|
1086 |
winFile *pFile = (winFile*)id; |
|
ds@1952
|
1087 |
void *zConverted = convertUtf8Filename(zName); |
|
ds@1952
|
1088 |
if( zConverted==0 ){ |
|
ds@1952
|
1089 |
return SQLITE_NOMEM; |
|
ds@1952
|
1090 |
} |
|
ds@1952
|
1091 |
|
|
ds@1952
|
1092 |
if( flags & SQLITE_OPEN_READWRITE ){ |
|
ds@1952
|
1093 |
dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; |
|
ds@1952
|
1094 |
}else{ |
|
ds@1952
|
1095 |
dwDesiredAccess = GENERIC_READ; |
|
ds@1952
|
1096 |
} |
|
ds@1952
|
1097 |
if( flags & SQLITE_OPEN_CREATE ){ |
|
ds@1952
|
1098 |
dwCreationDisposition = OPEN_ALWAYS; |
|
ds@1952
|
1099 |
}else{ |
|
ds@1952
|
1100 |
dwCreationDisposition = OPEN_EXISTING; |
|
ds@1952
|
1101 |
} |
|
ds@1952
|
1102 |
if( flags & SQLITE_OPEN_MAIN_DB ){ |
|
ds@1952
|
1103 |
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; |
|
ds@1952
|
1104 |
}else{ |
|
ds@1952
|
1105 |
dwShareMode = 0; |
|
ds@1952
|
1106 |
} |
|
ds@1952
|
1107 |
if( flags & (SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_TEMP_JOURNAL |
|
ds@1952
|
1108 |
| SQLITE_OPEN_SUBJOURNAL) ){ |
|
ds@1952
|
1109 |
dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY |
|
ds@1952
|
1110 |
| FILE_ATTRIBUTE_HIDDEN |
|
ds@1952
|
1111 |
| FILE_FLAG_DELETE_ON_CLOSE; |
|
ds@1952
|
1112 |
}else{ |
|
ds@1952
|
1113 |
dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; |
|
ds@1952
|
1114 |
} |
|
ds@1952
|
1115 |
if( flags & (SQLITE_OPEN_MAIN_DB | SQLITE_OPEN_TEMP_DB) ){ |
|
ds@1952
|
1116 |
dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS; |
|
ds@1952
|
1117 |
}else{ |
|
ds@1952
|
1118 |
dwFlagsAndAttributes |= FILE_FLAG_SEQUENTIAL_SCAN; |
|
ds@1952
|
1119 |
} |
|
ds@1952
|
1120 |
if( isNT() ){ |
|
ds@1952
|
1121 |
h = CreateFileW((WCHAR*)zConverted, |
|
ds@1952
|
1122 |
dwDesiredAccess, |
|
ds@1952
|
1123 |
dwShareMode, |
|
ds@1952
|
1124 |
NULL, |
|
ds@1952
|
1125 |
dwCreationDisposition, |
|
ds@1952
|
1126 |
dwFlagsAndAttributes, |
|
ds@1952
|
1127 |
NULL |
|
ds@1952
|
1128 |
); |
|
ds@1952
|
1129 |
}else{ |
|
ds@1952
|
1130 |
#if OS_WINCE |
|
ds@1952
|
1131 |
return SQLITE_NOMEM; |
|
ds@1952
|
1132 |
#else |
|
ds@1952
|
1133 |
h = CreateFileA((char*)zConverted, |
|
ds@1952
|
1134 |
dwDesiredAccess, |
|
ds@1952
|
1135 |
dwShareMode, |
|
ds@1952
|
1136 |
NULL, |
|
ds@1952
|
1137 |
dwCreationDisposition, |
|
ds@1952
|
1138 |
dwFlagsAndAttributes, |
|
ds@1952
|
1139 |
NULL |
|
ds@1952
|
1140 |
); |
|
ds@1952
|
1141 |
#endif |
|
ds@1952
|
1142 |
} |
|
ds@1952
|
1143 |
if( h==INVALID_HANDLE_VALUE ){ |
|
ds@1952
|
1144 |
free(zConverted); |
|
ds@1952
|
1145 |
if( flags & SQLITE_OPEN_READWRITE ){ |
|
ds@1952
|
1146 |
return winOpen(0, zName, id, |
|
ds@1952
|
1147 |
((flags|SQLITE_OPEN_READONLY)&~SQLITE_OPEN_READWRITE), pOutFlags); |
|
ds@1952
|
1148 |
}else{ |
|
ds@1952
|
1149 |
return SQLITE_CANTOPEN; |
|
ds@1952
|
1150 |
} |
|
ds@1952
|
1151 |
} |
|
ds@1952
|
1152 |
if( pOutFlags ){ |
|
ds@1952
|
1153 |
if( flags & SQLITE_OPEN_READWRITE ){ |
|
ds@1952
|
1154 |
*pOutFlags = SQLITE_OPEN_READWRITE; |
|
ds@1952
|
1155 |
}else{ |
|
ds@1952
|
1156 |
*pOutFlags = SQLITE_OPEN_READONLY; |
|
ds@1952
|
1157 |
} |
|
ds@1952
|
1158 |
} |
|
ds@1952
|
1159 |
memset(pFile, 0, sizeof(*pFile)); |
|
ds@1952
|
1160 |
pFile->pMethod = &winIoMethod; |
|
ds@1952
|
1161 |
pFile->h = h; |
|
ds@1952
|
1162 |
#if OS_WINCE |
|
ds@1952
|
1163 |
if( (flags & (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)) == |
|
ds@1952
|
1164 |
(SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB) |
|
ds@1952
|
1165 |
&& !winceCreateLock(zFilename, pFile) |
|
ds@1952
|
1166 |
){ |
|
ds@1952
|
1167 |
CloseHandle(h); |
|
ds@1952
|
1168 |
free(zConverted); |
|
ds@1952
|
1169 |
return SQLITE_CANTOPEN; |
|
ds@1952
|
1170 |
} |
|
ds@1952
|
1171 |
if( dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE ){ |
|
ds@1952
|
1172 |
pFile->zDeleteOnClose = zConverted; |
|
ds@1952
|
1173 |
}else |
|
ds@1952
|
1174 |
#endif |
|
ds@1952
|
1175 |
{ |
|
ds@1952
|
1176 |
free(zConverted); |
|
ds@1952
|
1177 |
} |
|
ds@1952
|
1178 |
OpenCounter(+1); |
|
ds@1952
|
1179 |
return SQLITE_OK; |
|
ds@1952
|
1180 |
} |
|
ds@1952
|
1181 |
|
|
ds@1952
|
1182 |
/* |
|
ds@1952
|
1183 |
** Delete the named file. |
|
ds@1952
|
1184 |
** |
|
ds@1952
|
1185 |
** Note that windows does not allow a file to be deleted if some other |
|
ds@1952
|
1186 |
** process has it open. Sometimes a virus scanner or indexing program |
|
ds@1952
|
1187 |
** will open a journal file shortly after it is created in order to do |
|
ds@1952
|
1188 |
** whatever it is it does. While this other process is holding the |
|
ds@1952
|
1189 |
** file open, we will be unable to delete it. To work around this |
|
ds@1952
|
1190 |
** problem, we delay 100 milliseconds and try to delete again. Up |
|
ds@1952
|
1191 |
** to MX_DELETION_ATTEMPTs deletion attempts are run before giving |
|
ds@1952
|
1192 |
** up and returning an error. |
|
ds@1952
|
1193 |
*/ |
|
ds@1952
|
1194 |
#define MX_DELETION_ATTEMPTS 3 |
|
ds@1952
|
1195 |
static int winDelete( |
|
ds@1952
|
1196 |
sqlite3_vfs *pVfs, /* Not used on win32 */ |
|
ds@1952
|
1197 |
const char *zFilename, /* Name of file to delete */ |
|
ds@1952
|
1198 |
int syncDir /* Not used on win32 */ |
|
ds@1952
|
1199 |
){ |
|
ds@1952
|
1200 |
int cnt = 0; |
|
ds@1952
|
1201 |
int rc; |
|
ds@1952
|
1202 |
void *zConverted = convertUtf8Filename(zFilename); |
|
ds@1952
|
1203 |
if( zConverted==0 ){ |
|
ds@1952
|
1204 |
return SQLITE_NOMEM; |
|
ds@1952
|
1205 |
} |
|
ds@1952
|
1206 |
SimulateIOError(return SQLITE_IOERR_DELETE); |
|
ds@1952
|
1207 |
if( isNT() ){ |
|
ds@1952
|
1208 |
do{ |
|
ds@1952
|
1209 |
rc = DeleteFileW(zConverted); |
|
ds@1952
|
1210 |
}while( rc==0 && GetFileAttributesW(zConverted)!=0xffffffff |
|
ds@1952
|
1211 |
&& cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) ); |
|
ds@1952
|
1212 |
}else{ |
|
ds@1952
|
1213 |
#if OS_WINCE |
|
ds@1952
|
1214 |
return SQLITE_NOMEM; |
|
ds@1952
|
1215 |
#else |
|
ds@1952
|
1216 |
do{ |
|
ds@1952
|
1217 |
rc = DeleteFileA(zConverted); |
|
ds@1952
|
1218 |
}while( rc==0 && GetFileAttributesA(zConverted)!=0xffffffff |
|
ds@1952
|
1219 |
&& cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) ); |
|
ds@1952
|
1220 |
#endif |
|
ds@1952
|
1221 |
} |
|
ds@1952
|
1222 |
free(zConverted); |
|
ds@1952
|
1223 |
OSTRACE2("DELETE \"%s\"\n", zFilename); |
|
ds@1952
|
1224 |
return rc!=0 ? SQLITE_OK : SQLITE_IOERR; |
|
ds@1952
|
1225 |
} |
|
ds@1952
|
1226 |
|
|
ds@1952
|
1227 |
/* |
|
ds@1952
|
1228 |
** Check the existance and status of a file. |
|
ds@1952
|
1229 |
*/ |
|
ds@1952
|
1230 |
static int winAccess( |
|
ds@1952
|
1231 |
sqlite3_vfs *pVfs, /* Not used on win32 */ |
|
ds@1952
|
1232 |
const char *zFilename, /* Name of file to check */ |
|
ds@1952
|
1233 |
int flags /* Type of test to make on this file */ |
|
ds@1952
|
1234 |
){ |
|
ds@1952
|
1235 |
DWORD attr; |
|
ds@1952
|
1236 |
int rc; |
|
ds@1952
|
1237 |
void *zConverted = convertUtf8Filename(zFilename); |
|
ds@1952
|
1238 |
if( zConverted==0 ){ |
|
ds@1952
|
1239 |
return SQLITE_NOMEM; |
|
ds@1952
|
1240 |
} |
|
ds@1952
|
1241 |
if( isNT() ){ |
|
ds@1952
|
1242 |
attr = GetFileAttributesW((WCHAR*)zConverted); |
|
ds@1952
|
1243 |
}else{ |
|
ds@1952
|
1244 |
#if OS_WINCE |
|
ds@1952
|
1245 |
return SQLITE_NOMEM; |
|
ds@1952
|
1246 |
#else |
|
ds@1952
|
1247 |
attr = GetFileAttributesA((char*)zConverted); |
|
ds@1952
|
1248 |
#endif |
|
ds@1952
|
1249 |
} |
|
ds@1952
|
1250 |
free(zConverted); |
|
ds@1952
|
1251 |
switch( flags ){ |
|
ds@1952
|
1252 |
case SQLITE_ACCESS_READ: |
|
ds@1952
|
1253 |
case SQLITE_ACCESS_EXISTS: |
|
ds@1952
|
1254 |
rc = attr!=0xffffffff; |
|
ds@1952
|
1255 |
break; |
|
ds@1952
|
1256 |
case SQLITE_ACCESS_READWRITE: |
|
ds@1952
|
1257 |
rc = (attr & FILE_ATTRIBUTE_READONLY)==0; |
|
ds@1952
|
1258 |
break; |
|
ds@1952
|
1259 |
default: |
|
ds@1952
|
1260 |
assert(!"Invalid flags argument"); |
|
ds@1952
|
1261 |
} |
|
ds@1952
|
1262 |
return rc; |
|
ds@1952
|
1263 |
} |
|
ds@1952
|
1264 |
|
|
ds@1952
|
1265 |
|
|
ds@1952
|
1266 |
/* |
|
ds@1952
|
1267 |
** Create a temporary file name in zBuf. zBuf must be big enough to |
|
ds@1952
|
1268 |
** hold at pVfs->mxPathname characters. |
|
ds@1952
|
1269 |
*/ |
|
ds@1952
|
1270 |
static int winGetTempname(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ |
|
ds@1952
|
1271 |
static char zChars[] = |
|
ds@1952
|
1272 |
"abcdefghijklmnopqrstuvwxyz" |
|
ds@1952
|
1273 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
|
ds@1952
|
1274 |
"0123456789"; |
|
ds@1952
|
1275 |
int i, j; |
|
ds@1952
|
1276 |
char zTempPath[MAX_PATH+1]; |
|
ds@1952
|
1277 |
if( sqlite3_temp_directory ){ |
|
ds@1952
|
1278 |
sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory); |
|
ds@1952
|
1279 |
}else if( isNT() ){ |
|
ds@1952
|
1280 |
char *zMulti; |
|
ds@1952
|
1281 |
WCHAR zWidePath[MAX_PATH]; |
|
ds@1952
|
1282 |
GetTempPathW(MAX_PATH-30, zWidePath); |
|
ds@1952
|
1283 |
zMulti = unicodeToUtf8(zWidePath); |
|
ds@1952
|
1284 |
if( zMulti ){ |
|
ds@1952
|
1285 |
sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti); |
|
ds@1952
|
1286 |
free(zMulti); |
|
ds@1952
|
1287 |
}else{ |
|
ds@1952
|
1288 |
return SQLITE_NOMEM; |
|
ds@1952
|
1289 |
} |
|
ds@1952
|
1290 |
}else{ |
|
ds@1952
|
1291 |
char *zUtf8; |
|
ds@1952
|
1292 |
char zMbcsPath[MAX_PATH]; |
|
ds@1952
|
1293 |
GetTempPathA(MAX_PATH-30, zMbcsPath); |
|
ds@1952
|
1294 |
zUtf8 = mbcsToUtf8(zMbcsPath); |
|
ds@1952
|
1295 |
if( zUtf8 ){ |
|
ds@1952
|
1296 |
sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8); |
|
ds@1952
|
1297 |
free(zUtf8); |
|
ds@1952
|
1298 |
}else{ |
|
ds@1952
|
1299 |
return SQLITE_NOMEM; |
|
ds@1952
|
1300 |
} |
|
ds@1952
|
1301 |
} |
|
ds@1952
|
1302 |
for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){} |
|
ds@1952
|
1303 |
zTempPath[i] = 0; |
|
ds@1952
|
1304 |
sqlite3_snprintf(pVfs->mxPathname-30, zBuf, |
|
ds@1952
|
1305 |
"%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath); |
|
ds@1952
|
1306 |
j = strlen(zBuf); |
|
ds@1952
|
1307 |
sqlite3Randomness(20, &zBuf[j]); |
|
ds@1952
|
1308 |
for(i=0; i<20; i++, j++){ |
|
ds@1952
|
1309 |
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; |
|
ds@1952
|
1310 |
} |
|
ds@1952
|
1311 |
zBuf[j] = 0; |
|
ds@1952
|
1312 |
OSTRACE2("TEMP FILENAME: %s\n", zBuf); |
|
ds@1952
|
1313 |
return SQLITE_OK; |
|
ds@1952
|
1314 |
} |
|
ds@1952
|
1315 |
|
|
ds@1952
|
1316 |
/* |
|
ds@1952
|
1317 |
** Turn a relative pathname into a full pathname. Write the full |
|
ds@1952
|
1318 |
** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname |
|
ds@1952
|
1319 |
** bytes in size. |
|
ds@1952
|
1320 |
*/ |
|
ds@1952
|
1321 |
static int winFullPathname( |
|
ds@1952
|
1322 |
sqlite3_vfs *pVfs, /* Pointer to vfs object */ |
|
ds@1952
|
1323 |
const char *zRelative, /* Possibly relative input path */ |
|
ds@1952
|
1324 |
int nFull, /* Size of output buffer in bytes */ |
|
ds@1952
|
1325 |
char *zFull /* Output buffer */ |
|
ds@1952
|
1326 |
){ |
|
ds@1952
|
1327 |
|
|
ds@1952
|
1328 |
#if defined(__CYGWIN__) |
|
ds@1952
|
1329 |
cygwin_conv_to_full_win32_path(zRelative, zFull); |
|
ds@1952
|
1330 |
return SQLITE_OK; |
|
ds@1952
|
1331 |
#endif |
|
ds@1952
|
1332 |
|
|
ds@1952
|
1333 |
#if OS_WINCE |
|
ds@1952
|
1334 |
/* WinCE has no concept of a relative pathname, or so I am told. */ |
|
ds@1952
|
1335 |
sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zRelative); |
|
ds@1952
|
1336 |
#endif |
|
ds@1952
|
1337 |
|
|
ds@1952
|
1338 |
#if !OS_WINCE && !defined(__CYGWIN__) |
|
ds@1952
|
1339 |
int nByte; |
|
ds@1952
|
1340 |
void *zConverted; |
|
ds@1952
|
1341 |
char *zOut; |
|
ds@1952
|
1342 |
zConverted = convertUtf8Filename(zRelative); |
|
ds@1952
|
1343 |
if( isNT() ){ |
|
ds@1952
|
1344 |
WCHAR *zTemp; |
|
ds@1952
|
1345 |
nByte = GetFullPathNameW((WCHAR*)zConverted, 0, 0, 0) + 3; |
|
ds@1952
|
1346 |
zTemp = malloc( nByte*sizeof(zTemp[0]) ); |
|
ds@1952
|
1347 |
if( zTemp==0 ){ |
|
ds@1952
|
1348 |
free(zConverted); |
|
ds@1952
|
1349 |
return SQLITE_NOMEM; |
|
ds@1952
|
1350 |
} |
|
ds@1952
|
1351 |
GetFullPathNameW((WCHAR*)zConverted, nByte, zTemp, 0); |
|
ds@1952
|
1352 |
free(zConverted); |
|
ds@1952
|
1353 |
zOut = unicodeToUtf8(zTemp); |
|
ds@1952
|
1354 |
free(zTemp); |
|
ds@1952
|
1355 |
}else{ |
|
ds@1952
|
1356 |
char *zTemp; |
|
ds@1952
|
1357 |
nByte = GetFullPathNameA((char*)zConverted, 0, 0, 0) + 3; |
|
ds@1952
|
1358 |
zTemp = malloc( nByte*sizeof(zTemp[0]) ); |
|
ds@1952
|
1359 |
if( zTemp==0 ){ |
|
ds@1952
|
1360 |
free(zConverted); |
|
ds@1952
|
1361 |
return SQLITE_NOMEM; |
|
ds@1952
|
1362 |
} |
|
ds@1952
|
1363 |
GetFullPathNameA((char*)zConverted, nByte, zTemp, 0); |
|
ds@1952
|
1364 |
free(zConverted); |
|
ds@1952
|
1365 |
zOut = mbcsToUtf8(zTemp); |
|
ds@1952
|
1366 |
free(zTemp); |
|
ds@1952
|
1367 |
} |
|
ds@1952
|
1368 |
if( zOut ){ |
|
ds@1952
|
1369 |
sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zOut); |
|
ds@1952
|
1370 |
free(zOut); |
|
ds@1952
|
1371 |
return SQLITE_OK; |
|
ds@1952
|
1372 |
}else{ |
|
ds@1952
|
1373 |
return SQLITE_NOMEM; |
|
ds@1952
|
1374 |
} |
|
ds@1952
|
1375 |
#endif |
|
ds@1952
|
1376 |
} |
|
ds@1952
|
1377 |
|
|
ds@1952
|
1378 |
#ifndef SQLITE_OMIT_LOAD_EXTENSION |
|
ds@1952
|
1379 |
/* |
|
ds@1952
|
1380 |
** Interfaces for opening a shared library, finding entry points |
|
ds@1952
|
1381 |
** within the shared library, and closing the shared library. |
|
ds@1952
|
1382 |
*/ |
|
ds@1952
|
1383 |
/* |
|
ds@1952
|
1384 |
** Interfaces for opening a shared library, finding entry points |
|
ds@1952
|
1385 |
** within the shared library, and closing the shared library. |
|
ds@1952
|
1386 |
*/ |
|
ds@1952
|
1387 |
static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ |
|
ds@1952
|
1388 |
HANDLE h; |
|
ds@1952
|
1389 |
void *zConverted = convertUtf8Filename(zFilename); |
|
ds@1952
|
1390 |
if( zConverted==0 ){ |
|
ds@1952
|
1391 |
return 0; |
|
ds@1952
|
1392 |
} |
|
ds@1952
|
1393 |
if( isNT() ){ |
|
ds@1952
|
1394 |
h = LoadLibraryW((WCHAR*)zConverted); |
|
ds@1952
|
1395 |
}else{ |
|
ds@1952
|
1396 |
#if OS_WINCE |
|
ds@1952
|
1397 |
return 0; |
|
ds@1952
|
1398 |
#else |
|
ds@1952
|
1399 |
h = LoadLibraryA((char*)zConverted); |
|
ds@1952
|
1400 |
#endif |
|
ds@1952
|
1401 |
} |
|
ds@1952
|
1402 |
free(zConverted); |
|
ds@1952
|
1403 |
return (void*)h; |
|
ds@1952
|
1404 |
} |
|
ds@1952
|
1405 |
static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ |
|
ds@1952
|
1406 |
FormatMessage( |
|
ds@1952
|
1407 |
FORMAT_MESSAGE_FROM_SYSTEM, |
|
ds@1952
|
1408 |
NULL, |
|
ds@1952
|
1409 |
GetLastError(), |
|
ds@1952
|
1410 |
0, |
|
ds@1952
|
1411 |
zBufOut, |
|
ds@1952
|
1412 |
nBuf-1, |
|
ds@1952
|
1413 |
0 |
|
ds@1952
|
1414 |
); |
|
ds@1952
|
1415 |
} |
|
ds@1952
|
1416 |
void *winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){ |
|
ds@1952
|
1417 |
#if OS_WINCE |
|
ds@1952
|
1418 |
/* The GetProcAddressA() routine is only available on wince. */ |
|
ds@1952
|
1419 |
return GetProcAddressA((HANDLE)pHandle, zSymbol); |
|
ds@1952
|
1420 |
#else |
|
ds@1952
|
1421 |
/* All other windows platforms expect GetProcAddress() to take |
|
ds@1952
|
1422 |
** an Ansi string regardless of the _UNICODE setting */ |
|
ds@1952
|
1423 |
return GetProcAddress((HANDLE)pHandle, zSymbol); |
|
ds@1952
|
1424 |
#endif |
|
ds@1952
|
1425 |
} |
|
ds@1952
|
1426 |
void winDlClose(sqlite3_vfs *pVfs, void *pHandle){ |
|
ds@1952
|
1427 |
FreeLibrary((HANDLE)pHandle); |
|
ds@1952
|
1428 |
} |
|
ds@1952
|
1429 |
#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ |
|
ds@1952
|
1430 |
#define winDlOpen 0 |
|
ds@1952
|
1431 |
#define winDlError 0 |
|
ds@1952
|
1432 |
#define winDlSym 0 |
|
ds@1952
|
1433 |
#define winDlClose 0 |
|
ds@1952
|
1434 |
#endif |
|
ds@1952
|
1435 |
|
|
ds@1952
|
1436 |
|
|
ds@1952
|
1437 |
/* |
|
ds@1952
|
1438 |
** Write up to nBuf bytes of randomness into zBuf. |
|
ds@1952
|
1439 |
*/ |
|
ds@1952
|
1440 |
static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ |
|
ds@1952
|
1441 |
int n = 0; |
|
ds@1952
|
1442 |
if( sizeof(SYSTEMTIME)<=nBuf-n ){ |
|
ds@1952
|
1443 |
SYSTEMTIME x; |
|
ds@1952
|
1444 |
GetSystemTime(&x); |
|
ds@1952
|
1445 |
memcpy(&zBuf[n], &x, sizeof(x)); |
|
ds@1952
|
1446 |
n += sizeof(x); |
|
ds@1952
|
1447 |
} |
|
ds@1952
|
1448 |
if( sizeof(DWORD)<=nBuf-n ){ |
|
ds@1952
|
1449 |
DWORD pid = GetCurrentProcessId(); |
|
ds@1952
|
1450 |
memcpy(&zBuf[n], &pid, sizeof(pid)); |
|
ds@1952
|
1451 |
n += sizeof(pid); |
|
ds@1952
|
1452 |
} |
|
ds@1952
|
1453 |
if( sizeof(DWORD)<=nBuf-n ){ |
|
ds@1952
|
1454 |
DWORD cnt = GetTickCount(); |
|
ds@1952
|
1455 |
memcpy(&zBuf[n], &cnt, sizeof(cnt)); |
|
ds@1952
|
1456 |
n += sizeof(cnt); |
|
ds@1952
|
1457 |
} |
|
ds@1952
|
1458 |
if( sizeof(LARGE_INTEGER)<=nBuf-n ){ |
|
ds@1952
|
1459 |
LARGE_INTEGER i; |
|
ds@1952
|
1460 |
QueryPerformanceCounter(&i); |
|
ds@1952
|
1461 |
memcpy(&zBuf[n], &i, sizeof(i)); |
|
ds@1952
|
1462 |
n += sizeof(i); |
|
ds@1952
|
1463 |
} |
|
ds@1952
|
1464 |
return n; |
|
ds@1952
|
1465 |
} |
|
ds@1952
|
1466 |
|
|
ds@1952
|
1467 |
|
|
ds@1952
|
1468 |
/* |
|
ds@1952
|
1469 |
** Sleep for a little while. Return the amount of time slept. |
|
ds@1952
|
1470 |
*/ |
|
ds@1952
|
1471 |
static int winSleep(sqlite3_vfs *pVfs, int microsec){ |
|
ds@1952
|
1472 |
Sleep((microsec+999)/1000); |
|
ds@1952
|
1473 |
return ((microsec+999)/1000)*1000; |
|
ds@1952
|
1474 |
} |
|
ds@1952
|
1475 |
|
|
ds@1952
|
1476 |
/* |
|
ds@1952
|
1477 |
** The following variable, if set to a non-zero value, becomes the result |
|
ds@1952
|
1478 |
** returned from sqlite3OsCurrentTime(). This is used for testing. |
|
ds@1952
|
1479 |
*/ |
|
ds@1952
|
1480 |
#ifdef SQLITE_TEST |
|
ds@1952
|
1481 |
int sqlite3_current_time = 0; |
|
ds@1952
|
1482 |
#endif |
|
ds@1952
|
1483 |
|
|
ds@1952
|
1484 |
/* |
|
ds@1952
|
1485 |
** Find the current time (in Universal Coordinated Time). Write the |
|
ds@1952
|
1486 |
** current time and date as a Julian Day number into *prNow and |
|
ds@1952
|
1487 |
** return 0. Return 1 if the time and date cannot be found. |
|
ds@1952
|
1488 |
*/ |
|
ds@1952
|
1489 |
int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){ |
|
ds@1952
|
1490 |
FILETIME ft; |
|
ds@1952
|
1491 |
/* FILETIME structure is a 64-bit value representing the number of |
|
ds@1952
|
1492 |
100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). |
|
ds@1952
|
1493 |
*/ |
|
ds@1952
|
1494 |
double now; |
|
ds@1952
|
1495 |
#if OS_WINCE |
|
ds@1952
|
1496 |
SYSTEMTIME time; |
|
ds@1952
|
1497 |
GetSystemTime(&time); |
|
ds@1952
|
1498 |
SystemTimeToFileTime(&time,&ft); |
|
ds@1952
|
1499 |
#else |
|
ds@1952
|
1500 |
GetSystemTimeAsFileTime( &ft ); |
|
ds@1952
|
1501 |
#endif |
|
ds@1952
|
1502 |
now = ((double)ft.dwHighDateTime) * 4294967296.0; |
|
ds@1952
|
1503 |
*prNow = (now + ft.dwLowDateTime)/864000000000.0 + 2305813.5; |
|
ds@1952
|
1504 |
#ifdef SQLITE_TEST |
|
ds@1952
|
1505 |
if( sqlite3_current_time ){ |
|
ds@1952
|
1506 |
*prNow = sqlite3_current_time/86400.0 + 2440587.5; |
|
ds@1952
|
1507 |
} |
|
ds@1952
|
1508 |
#endif |
|
ds@1952
|
1509 |
return 0; |
|
ds@1952
|
1510 |
} |
|
ds@1952
|
1511 |
|
|
ds@1952
|
1512 |
|
|
ds@1952
|
1513 |
/* |
|
ds@1952
|
1514 |
** Return a pointer to the sqlite3DefaultVfs structure. We use |
|
ds@1952
|
1515 |
** a function rather than give the structure global scope because |
|
ds@1952
|
1516 |
** some compilers (MSVC) do not allow forward declarations of |
|
ds@1952
|
1517 |
** initialized structures. |
|
ds@1952
|
1518 |
*/ |
|
ds@1952
|
1519 |
sqlite3_vfs *sqlite3OsDefaultVfs(void){ |
|
ds@1952
|
1520 |
static sqlite3_vfs winVfs = { |
|
ds@1952
|
1521 |
1, /* iVersion */ |
|
ds@1952
|
1522 |
sizeof(winFile), /* szOsFile */ |
|
ds@1952
|
1523 |
MAX_PATH, /* mxPathname */ |
|
ds@1952
|
1524 |
0, /* pNext */ |
|
ds@1952
|
1525 |
"win32", /* zName */ |
|
ds@1952
|
1526 |
0, /* pAppData */ |
|
ds@1952
|
1527 |
|
|
ds@1952
|
1528 |
winOpen, /* xOpen */ |
|
ds@1952
|
1529 |
winDelete, /* xDelete */ |
|
ds@1952
|
1530 |
winAccess, /* xAccess */ |
|
ds@1952
|
1531 |
winGetTempname, /* xGetTempName */ |
|
ds@1952
|
1532 |
winFullPathname, /* xFullPathname */ |
|
ds@1952
|
1533 |
winDlOpen, /* xDlOpen */ |
|
ds@1952
|
1534 |
winDlError, /* xDlError */ |
|
ds@1952
|
1535 |
winDlSym, /* xDlSym */ |
|
ds@1952
|
1536 |
winDlClose, /* xDlClose */ |
|
ds@1952
|
1537 |
winRandomness, /* xRandomness */ |
|
ds@1952
|
1538 |
winSleep, /* xSleep */ |
|
ds@1952
|
1539 |
winCurrentTime /* xCurrentTime */ |
|
ds@1952
|
1540 |
}; |
|
ds@1952
|
1541 |
|
|
ds@1952
|
1542 |
return &winVfs; |
|
ds@1952
|
1543 |
} |
|
ds@1952
|
1544 |
|
|
ds@1952
|
1545 |
#endif /* OS_WIN */ |