|
1 /* |
|
2 ** 2008 February 09 |
|
3 ** |
|
4 ** The author disclaims copyright to this source code. In place of |
|
5 ** a legal notice, here is a blessing: |
|
6 ** |
|
7 ** May you do good and not evil. |
|
8 ** May you find forgiveness for yourself and forgive others. |
|
9 ** May you share freely, never taking more than you give. |
|
10 ** |
|
11 ****************************************************************************** |
|
12 ** |
|
13 ** This file contains code that is specific to windows. |
|
14 */ |
|
15 #include "sqliteInt.h" |
|
16 #if OS_SYMBIAN /* This file is used for symbian only */ |
|
17 |
|
18 #define MAX_PATH 260 |
|
19 /* |
|
20 ** A Note About Memory Allocation: |
|
21 ** |
|
22 ** This driver uses malloc()/free() directly rather than going through |
|
23 ** the SQLite-wrappers sqlite3_malloc()/sqlite3_free(). Those wrappers |
|
24 ** are designed for use on embedded systems where memory is scarce and |
|
25 ** malloc failures happen frequently. Win32 does not typically run on |
|
26 ** embedded systems, and when it does the developers normally have bigger |
|
27 ** problems to worry about than running out of memory. So there is not |
|
28 ** a compelling need to use the wrappers. |
|
29 ** |
|
30 ** But there is a good reason to not use the wrappers. If we use the |
|
31 ** wrappers then we will get simulated malloc() failures within this |
|
32 ** driver. And that causes all kinds of problems for our tests. We |
|
33 ** could enhance SQLite to deal with simulated malloc failures within |
|
34 ** the OS driver, but the code to deal with those failure would not |
|
35 ** be exercised on Linux (which does not need to malloc() in the driver) |
|
36 ** and so we would have difficulty writing coverage tests for that |
|
37 ** code. Better to leave the code out, we think. |
|
38 ** |
|
39 ** The point of this discussion is as follows: When creating a new |
|
40 ** OS layer for an embedded system, if you use this file as an example, |
|
41 ** avoid the use of malloc()/free(). Those routines work ok on windows |
|
42 ** desktops but not so well in embedded systems. |
|
43 */ |
|
44 |
|
45 #include <stdlib.h> |
|
46 #include <string.h> |
|
47 #include <time.h> |
|
48 #include <e32std.h> |
|
49 #include <f32file.h> |
|
50 #include <charconv.h> |
|
51 #include <bautils.h> |
|
52 #include <unistd.h> |
|
53 |
|
54 /* |
|
55 ** Macros used to determine whether or not to use threads. |
|
56 */ |
|
57 #if defined(THREADSAFE) && THREADSAFE |
|
58 # define SQLITE_W32_THREADS 1 |
|
59 #endif |
|
60 |
|
61 /* |
|
62 ** Include code that is common to all os_*.c files |
|
63 */ |
|
64 #include "os_common.h" |
|
65 |
|
66 /* |
|
67 ** The symbianFile structure is a subclass of sqlite3_file* specific to the win32 |
|
68 ** portability layer. |
|
69 */ |
|
70 |
|
71 typedef struct symbianFile symbianFile; |
|
72 struct symbianFile { |
|
73 int isOpen; |
|
74 unsigned char locktype; /* Type of lock currently held on this file */ |
|
75 short sharedLockByte; /* Randomly chosen byte used as a shared lock */ |
|
76 char fileName[512]; |
|
77 RFs session; |
|
78 RFile file; |
|
79 }; |
|
80 |
|
81 /***************************************************************************** |
|
82 ** The next group of routines implement the I/O methods specified |
|
83 ** by the sqlite3_io_methods object. |
|
84 ******************************************************************************/ |
|
85 |
|
86 /* |
|
87 ** Close a file. |
|
88 ** |
|
89 ** It is reported that an attempt to close a handle might sometimes |
|
90 ** fail. This is a very unreasonable result, but windows is notorious |
|
91 ** for being unreasonable so I do not doubt that it might happen. If |
|
92 ** the close fails, we pause for 100 milliseconds and try again. As |
|
93 ** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before |
|
94 ** giving up and returning an error. |
|
95 */ |
|
96 #define MX_CLOSE_ATTEMPT 3 |
|
97 int winClose(sqlite3_file *id){ |
|
98 int rc, cnt = 0; |
|
99 symbianFile *pFile = (symbianFile*)id; |
|
100 pFile->file.Close(); |
|
101 pFile->session.Close(); |
|
102 return SQLITE_OK; |
|
103 } |
|
104 |
|
105 /* |
|
106 ** Some microsoft compilers lack this definition. |
|
107 */ |
|
108 #ifndef INVALID_SET_FILE_POINTER |
|
109 # define INVALID_SET_FILE_POINTER ((DWORD)-1) |
|
110 #endif |
|
111 |
|
112 /* |
|
113 ** Read data from a file into a buffer. Return SQLITE_OK if all |
|
114 ** bytes were read successfully and SQLITE_IOERR if anything goes |
|
115 ** wrong. |
|
116 */ |
|
117 int winRead( |
|
118 sqlite3_file *id, /* File to read from */ |
|
119 void *pBuf, /* Write content into this buffer */ |
|
120 int amt, /* Number of bytes to read */ |
|
121 sqlite3_int64 offset /* Begin reading at this offset */ |
|
122 ){ |
|
123 int rc; |
|
124 size_t got; |
|
125 symbianFile *pFile = (symbianFile*)id; |
|
126 assert( id!=0 ); |
|
127 SimulateIOError(return SQLITE_IOERR_READ); |
|
128 TInt tOffset = (TInt)offset; |
|
129 rc = pFile->file.Seek(ESeekStart, tOffset); |
|
130 if( rc!= KErrNone){ |
|
131 return SQLITE_FULL; |
|
132 } |
|
133 |
|
134 HBufC8* buf = HBufC8::NewL(amt) ; |
|
135 TPtr8 ptr = buf->Des(); |
|
136 |
|
137 if (pFile->file.Read(ptr, amt) != KErrNone) |
|
138 { |
|
139 delete buf; |
|
140 return SQLITE_IOERR_READ; |
|
141 } |
|
142 |
|
143 got = buf->Length(); |
|
144 |
|
145 if( got == 0 ){ |
|
146 delete buf; |
|
147 TInt size = 0; |
|
148 if (pFile->file.Size(size) != KErrNone) |
|
149 { |
|
150 return SQLITE_IOERR_READ; |
|
151 } |
|
152 if (size == 0) |
|
153 { |
|
154 return SQLITE_IOERR_SHORT_READ; |
|
155 } |
|
156 return SQLITE_IOERR_READ; |
|
157 } |
|
158 memcpy(pBuf, ptr.Ptr(), got); |
|
159 delete buf; |
|
160 if( got == amt ){ |
|
161 return SQLITE_OK; |
|
162 }else{ |
|
163 memset(&((char*)pBuf)[got], 0, amt-got); |
|
164 return SQLITE_IOERR_SHORT_READ; |
|
165 } |
|
166 } |
|
167 |
|
168 /* |
|
169 ** Write data from a buffer into a file. Return SQLITE_OK on success |
|
170 ** or some other error code on failure. |
|
171 */ |
|
172 int winWrite( |
|
173 sqlite3_file *id, /* File to write into */ |
|
174 const void *pBuf, /* The bytes to be written */ |
|
175 int amt, /* Number of bytes to write */ |
|
176 sqlite3_int64 offset /* Offset into the file to begin writing at */ |
|
177 ){ |
|
178 int rc; |
|
179 symbianFile *pFile = (symbianFile*)id; |
|
180 assert( id!=0 ); |
|
181 SimulateIOError(return SQLITE_IOERR_WRITE); |
|
182 SimulateDiskfullError(return SQLITE_FULL); |
|
183 TInt tOffset = (TInt)offset; |
|
184 rc = pFile->file.Seek(ESeekStart, tOffset); |
|
185 if( rc!= KErrNone){ |
|
186 return SQLITE_FULL; |
|
187 } |
|
188 |
|
189 assert( amt>0 ); |
|
190 |
|
191 rc = SQLITE_OK; |
|
192 TPtrC8 ptr((TUint8 *)pBuf,amt); |
|
193 |
|
194 if (pFile->file.Write(ptr, amt) != KErrNone) rc = SQLITE_FULL; |
|
195 |
|
196 return rc; |
|
197 } |
|
198 |
|
199 /* |
|
200 ** Truncate an open file to a specified size |
|
201 */ |
|
202 int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ |
|
203 symbianFile *pFile = (symbianFile*)id; |
|
204 |
|
205 if (pFile->file.SetSize(nByte) != KErrNone) |
|
206 { |
|
207 return SQLITE_IOERR; |
|
208 } |
|
209 |
|
210 return SQLITE_OK; |
|
211 } |
|
212 |
|
213 #ifdef SQLITE_TEST |
|
214 /* |
|
215 ** Count the number of fullsyncs and normal syncs. This is used to test |
|
216 ** that syncs and fullsyncs are occuring at the right times. |
|
217 */ |
|
218 int sqlite3_sync_count = 0; |
|
219 int sqlite3_fullsync_count = 0; |
|
220 #endif |
|
221 |
|
222 /* |
|
223 ** Make sure all writes to a particular file are committed to disk. |
|
224 */ |
|
225 int winSync(sqlite3_file *id, int flags){ |
|
226 symbianFile *pFile = (symbianFile*)id; |
|
227 OSTRACE3("SYNC %d lock=%d\n", pFile->h, pFile->locktype); |
|
228 #ifdef SQLITE_TEST |
|
229 if( flags & SQLITE_SYNC_FULL ){ |
|
230 sqlite3_fullsync_count++; |
|
231 } |
|
232 sqlite3_sync_count++; |
|
233 #endif |
|
234 TInt error = pFile->file.Flush(); |
|
235 if (error != KErrNone) |
|
236 { |
|
237 return SQLITE_IOERR; |
|
238 }else{ |
|
239 return SQLITE_OK; |
|
240 } |
|
241 } |
|
242 |
|
243 /* |
|
244 ** Determine the current size of a file in bytes |
|
245 */ |
|
246 int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ |
|
247 symbianFile *pFile = (symbianFile*)id; |
|
248 |
|
249 TInt size = 0; |
|
250 if (pFile->file.Size(size) != KErrNone) |
|
251 { |
|
252 return SQLITE_IOERR; |
|
253 } |
|
254 |
|
255 *pSize = size; |
|
256 |
|
257 return SQLITE_OK; |
|
258 } |
|
259 |
|
260 |
|
261 /* |
|
262 ** Lock the file with the lock specified by parameter locktype - one |
|
263 ** of the following: |
|
264 ** |
|
265 ** (1) SHARED_LOCK |
|
266 ** (2) RESERVED_LOCK |
|
267 ** (3) PENDING_LOCK |
|
268 ** (4) EXCLUSIVE_LOCK |
|
269 ** |
|
270 ** Sometimes when requesting one lock state, additional lock states |
|
271 ** are inserted in between. The locking might fail on one of the later |
|
272 ** transitions leaving the lock state different from what it started but |
|
273 ** still short of its goal. The following chart shows the allowed |
|
274 ** transitions and the inserted intermediate states: |
|
275 ** |
|
276 ** UNLOCKED -> SHARED |
|
277 ** SHARED -> RESERVED |
|
278 ** SHARED -> (PENDING) -> EXCLUSIVE |
|
279 ** RESERVED -> (PENDING) -> EXCLUSIVE |
|
280 ** PENDING -> EXCLUSIVE |
|
281 ** |
|
282 ** This routine will only increase a lock. The winUnlock() routine |
|
283 ** erases all locks at once and returns us immediately to locking level 0. |
|
284 ** It is not possible to lower the locking level one step at a time. You |
|
285 ** must go straight to locking level 0. |
|
286 */ |
|
287 int winLock(sqlite3_file *id, int locktype){ |
|
288 int rc = SQLITE_OK; /* Return code from subroutines */ |
|
289 int res = 1; /* Result of a windows lock call */ |
|
290 int newLocktype; /* Set pFile->locktype to this value before exiting */ |
|
291 int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ |
|
292 symbianFile *pFile = (symbianFile*)id; |
|
293 |
|
294 assert( pFile!=0 ); |
|
295 OSTRACE5("LOCK %d %d was %d(%d)\n", |
|
296 pFile->h, locktype, pFile->locktype, pFile->sharedLockByte); |
|
297 |
|
298 // one smartphone only one application can control the database |
|
299 |
|
300 TInt size = 0; |
|
301 if (pFile->file.Size(size) == KErrNone) return SQLITE_OK; |
|
302 |
|
303 return SQLITE_BUSY; |
|
304 } |
|
305 |
|
306 /* |
|
307 ** This routine checks if there is a RESERVED lock held on the specified |
|
308 ** file by this or any other process. If such a lock is held, return |
|
309 ** non-zero, otherwise zero. |
|
310 */ |
|
311 int winCheckReservedLock(sqlite3_file *id){ |
|
312 int rc; |
|
313 symbianFile *pFile = (symbianFile*)id; |
|
314 assert( pFile!=0 ); |
|
315 if( pFile->locktype>=RESERVED_LOCK ){ |
|
316 rc = 1; |
|
317 OSTRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc); |
|
318 }else{ |
|
319 TInt size = 0; |
|
320 if (pFile->file.Size(size) == KErrNone) rc = 1; |
|
321 OSTRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc); |
|
322 } |
|
323 return rc; |
|
324 } |
|
325 |
|
326 /* |
|
327 ** Lower the locking level on file descriptor id to locktype. locktype |
|
328 ** must be either NO_LOCK or SHARED_LOCK. |
|
329 ** |
|
330 ** If the locking level of the file descriptor is already at or below |
|
331 ** the requested locking level, this routine is a no-op. |
|
332 ** |
|
333 ** It is not possible for this routine to fail if the second argument |
|
334 ** is NO_LOCK. If the second argument is SHARED_LOCK then this routine |
|
335 ** might return SQLITE_IOERR; |
|
336 */ |
|
337 int winUnlock(sqlite3_file *id, int locktype){ |
|
338 int type; |
|
339 symbianFile *pFile = (symbianFile*)id; |
|
340 int rc = SQLITE_OK; |
|
341 assert( pFile!=0 ); |
|
342 return rc; |
|
343 } |
|
344 |
|
345 /* |
|
346 ** Control and query of the open file handle. |
|
347 */ |
|
348 int winFileControl(sqlite3_file *id, int op, void *pArg){ |
|
349 switch( op ){ |
|
350 case SQLITE_FCNTL_LOCKSTATE: { |
|
351 *(int*)pArg = ((symbianFile*)id)->locktype; |
|
352 return SQLITE_OK; |
|
353 } |
|
354 } |
|
355 return SQLITE_ERROR; |
|
356 } |
|
357 |
|
358 /* |
|
359 ** Return the sector size in bytes of the underlying block device for |
|
360 ** the specified file. This is almost always 512 bytes, but may be |
|
361 ** larger for some devices. |
|
362 ** |
|
363 ** SQLite code assumes this function cannot fail. It also assumes that |
|
364 ** if two files are created in the same file-system directory (i.e. |
|
365 ** a database and its journal file) that the sector size will be the |
|
366 ** same for both. |
|
367 */ |
|
368 int winSectorSize(sqlite3_file *id){ |
|
369 return SQLITE_DEFAULT_SECTOR_SIZE; |
|
370 } |
|
371 |
|
372 /* |
|
373 ** Return a vector of device characteristics. |
|
374 */ |
|
375 int winDeviceCharacteristics(sqlite3_file *id){ |
|
376 return 0; |
|
377 } |
|
378 |
|
379 |
|
380 /*************************************************************************** |
|
381 ** Here ends the I/O methods that form the sqlite3_io_methods object. |
|
382 ** |
|
383 ** The next block of code implements the VFS methods. |
|
384 ****************************************************************************/ |
|
385 |
|
386 void ConvertToUnicode(RFs session, TDes16& aUnicode, const char *str) |
|
387 { |
|
388 CCnvCharacterSetConverter *converter = CCnvCharacterSetConverter::NewL(); |
|
389 converter->PrepareToConvertToOrFromL(KCharacterSetIdentifierUtf8, session); |
|
390 |
|
391 TPtrC8 ptr((const unsigned char*)str); |
|
392 |
|
393 int state = CCnvCharacterSetConverter::KStateDefault; |
|
394 converter->ConvertToUnicode(aUnicode, ptr, state); |
|
395 delete converter; |
|
396 } |
|
397 |
|
398 /* |
|
399 ** Open a file. |
|
400 */ |
|
401 int winOpen( |
|
402 sqlite3_vfs *pVfs, /* Not used */ |
|
403 const char *zName, /* Name of the file (UTF-8) */ |
|
404 sqlite3_file *id, /* Write the SQLite file handle here */ |
|
405 int flags, /* Open mode flags */ |
|
406 int *pOutFlags /* Status return flags */ |
|
407 ){ |
|
408 symbianFile *pFile = (symbianFile*)id; |
|
409 TBuf16<MAX_PATH> filename; |
|
410 |
|
411 pFile->isOpen = 0; |
|
412 memset(pFile, 0, sizeof(*pFile)); |
|
413 strcpy(pFile->fileName, zName); |
|
414 pFile->session.Connect(); |
|
415 |
|
416 ConvertToUnicode(pFile->session, filename, zName); |
|
417 |
|
418 int ret = 0; |
|
419 if( flags & SQLITE_OPEN_CREATE ){ |
|
420 if (BaflUtils::FileExists(pFile->session, filename) == 1) |
|
421 { |
|
422 ret = pFile->file.Open(pFile->session, filename, EFileStream | EFileWrite); |
|
423 } |
|
424 else |
|
425 { |
|
426 ret = pFile->file.Create(pFile->session, filename, EFileStream | EFileWrite); |
|
427 } |
|
428 } |
|
429 else |
|
430 if( flags & SQLITE_OPEN_READWRITE ){ |
|
431 ret = pFile->file.Open(pFile->session, filename, EFileStream | EFileWrite); |
|
432 }else{ |
|
433 ret = pFile->file.Open(pFile->session, filename, EFileStream | EFileRead); |
|
434 } |
|
435 |
|
436 OpenCounter(+1); |
|
437 |
|
438 if (ret != KErrNone) |
|
439 { |
|
440 return SQLITE_IOERR; |
|
441 } |
|
442 |
|
443 pFile->isOpen = 1; |
|
444 return SQLITE_OK; |
|
445 } |
|
446 |
|
447 /* |
|
448 ** Delete the named file. |
|
449 ** |
|
450 ** Note that windows does not allow a file to be deleted if some other |
|
451 ** process has it open. Sometimes a virus scanner or indexing program |
|
452 ** will open a journal file shortly after it is created in order to do |
|
453 ** whatever does. While this other process is holding the |
|
454 ** file open, we will be unable to delete it. To work around this |
|
455 ** problem, we delay 100 milliseconds and try to delete again. Up |
|
456 ** to MX_DELETION_ATTEMPTs deletion attempts are run before giving |
|
457 ** up and returning an error. |
|
458 */ |
|
459 #define MX_DELETION_ATTEMPTS 5 |
|
460 int winDelete( |
|
461 sqlite3_vfs *pVfs, /* Not used on win32 */ |
|
462 const char *zFilename, /* Name of file to delete */ |
|
463 int syncDir /* Not used on win32 */ |
|
464 ){ |
|
465 SimulateIOError(return SQLITE_IOERR_DELETE); |
|
466 TBuf16<MAX_PATH> filename; |
|
467 |
|
468 RFs session; |
|
469 session.Connect(); |
|
470 ConvertToUnicode(session, filename, zFilename); |
|
471 BaflUtils::DeleteFile(session, filename); |
|
472 OSTRACE2("DELETE \"%s\"\n", zFilename); |
|
473 session.Close(); |
|
474 return SQLITE_OK; |
|
475 } |
|
476 |
|
477 /* |
|
478 ** Check the existance and status of a file. |
|
479 */ |
|
480 int winAccess( |
|
481 sqlite3_vfs *pVfs, /* Not used on win32 */ |
|
482 const char *zFilename, /* Name of file to check */ |
|
483 int flags /* Type of test to make on this file */ |
|
484 ){ |
|
485 TBuf16<MAX_PATH> filename; |
|
486 |
|
487 RFs session; |
|
488 session.Connect(); |
|
489 ConvertToUnicode(session, filename, zFilename); |
|
490 int ret = BaflUtils::FileExists(session, filename); |
|
491 session.Close(); |
|
492 |
|
493 return ret; |
|
494 } |
|
495 |
|
496 |
|
497 /* |
|
498 ** Create a temporary file name in zBuf. zBuf must be big enough to |
|
499 ** hold at pVfs->mxPathname characters. |
|
500 */ |
|
501 int winGetTempname(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ |
|
502 static char zChars[] = |
|
503 "abcdefghijklmnopqrstuvwxyz" |
|
504 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
|
505 "0123456789"; |
|
506 int i, j; |
|
507 char zTempPath[MAX_PATH+1]; |
|
508 if( sqlite3_temp_directory ){ |
|
509 sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory); |
|
510 } |
|
511 else |
|
512 { |
|
513 } |
|
514 |
|
515 for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){} |
|
516 zTempPath[i] = 0; |
|
517 sqlite3_snprintf(nBuf-30, zBuf, |
|
518 "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath); |
|
519 j = strlen(zBuf); |
|
520 sqlite3Randomness(20, &zBuf[j]); |
|
521 for(i=0; i<20; i++, j++){ |
|
522 zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; |
|
523 } |
|
524 zBuf[j] = 0; |
|
525 OSTRACE2("TEMP FILENAME: %s\n", zBuf); |
|
526 return SQLITE_OK; |
|
527 } |
|
528 |
|
529 /* |
|
530 ** Turn a relative pathname into a full pathname. Write the full |
|
531 ** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname |
|
532 ** bytes in size. |
|
533 */ |
|
534 int winFullPathname( |
|
535 sqlite3_vfs *pVfs, /* Pointer to vfs object */ |
|
536 const char *zRelative, /* Possibly relative input path */ |
|
537 int nFull, /* Size of output buffer in bytes */ |
|
538 char *zFull /* Output buffer */ |
|
539 ){ |
|
540 |
|
541 /* WinCE has no concept of a relative pathname, or so I am told. */ |
|
542 sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zRelative); |
|
543 return SQLITE_OK; |
|
544 } |
|
545 |
|
546 #define winDlOpen 0 |
|
547 #define winDlError 0 |
|
548 #define winDlSym 0 |
|
549 #define winDlClose 0 |
|
550 |
|
551 |
|
552 /* |
|
553 ** Write up to nBuf bytes of randomness into zBuf. |
|
554 */ |
|
555 int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ |
|
556 |
|
557 int i; |
|
558 for (i=0; i<nBuf; ++i) |
|
559 { |
|
560 zBuf[i] = rand() % 255; |
|
561 } |
|
562 return nBuf; |
|
563 } |
|
564 |
|
565 |
|
566 /* |
|
567 ** Sleep for a little while. Return the amount of time slept. |
|
568 */ |
|
569 int winSleep(sqlite3_vfs *pVfs, int microsec){ |
|
570 return sleep(microsec / 1000); |
|
571 } |
|
572 |
|
573 /* |
|
574 ** The following variable, if set to a non-zero value, becomes the result |
|
575 ** returned from sqlite3OsCurrentTime(). This is used for testing. |
|
576 */ |
|
577 #ifdef SQLITE_TEST |
|
578 int sqlite3_current_time = 0; |
|
579 #endif |
|
580 |
|
581 /* |
|
582 ** Find the current time (in Universal Coordinated Time). Write the |
|
583 ** current time and date as a Julian Day number into *prNow and |
|
584 ** return 0. Return 1 if the time and date cannot be found. |
|
585 */ |
|
586 int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){ |
|
587 double now; |
|
588 |
|
589 now = time(NULL); |
|
590 *prNow = now; |
|
591 |
|
592 return 0; |
|
593 } |
|
594 |
|
595 |
|
596 /* |
|
597 ** Return a pointer to the sqlite3DefaultVfs structure. We use |
|
598 ** a function rather than give the structure global scope because |
|
599 ** some compilers (MSVC) do not allow forward declarations of |
|
600 ** initialized structures. |
|
601 */ |
|
602 sqlite3_vfs *sqlite3OsDefaultVfs(void){ |
|
603 static sqlite3_vfs winVfs = { |
|
604 1, /* iVersion */ |
|
605 -1, /* szOsFile */ |
|
606 MAX_PATH, /* mxPathname */ |
|
607 0, /* pNext */ |
|
608 "symbian", /* zName */ |
|
609 0, /* pAppData */ |
|
610 }; |
|
611 |
|
612 winVfs.szOsFile = sizeof(symbianFile); |
|
613 return &winVfs; |
|
614 } |
|
615 |
|
616 #endif /* OS_SYMBIAN */ |