|
1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // os_symbian.cpp |
|
15 // The Symbian OS porting layer - multi-threaded implementation. |
|
16 // SQLite never accesses the file system and the OS services directly. |
|
17 // SQLite uses for that sqlite3_vfs and sqlite3_file objects. |
|
18 // sqlite3_vfs and sqlite3_file functionality is implemented in this file - |
|
19 // TVfs and TFileIo classes. |
|
20 // |
|
21 // |
|
22 |
|
23 /** |
|
24 @file |
|
25 @see TVfs |
|
26 @see TFileIo |
|
27 */ |
|
28 |
|
29 #ifdef SQLITE_OS_SYMBIAN |
|
30 |
|
31 extern "C" |
|
32 { |
|
33 #include "sqliteInt.h" |
|
34 #include "os.h" |
|
35 #include "os_common.h" |
|
36 } |
|
37 #include <e32math.h> |
|
38 #include "os_symbian.h" |
|
39 #include "UTraceSqlite.h" |
|
40 |
|
41 #ifdef SQLITE_TEST |
|
42 |
|
43 //Count the number of fullsyncs and normal syncs. This is used to test |
|
44 //that syncs and fullsyncs are occuring at the right times. |
|
45 extern "C" int sqlite3_sync_count = 0; |
|
46 extern "C" int sqlite3_fullsync_count = 0; |
|
47 |
|
48 //The following variable, if set to a non-zero value, becomes the result |
|
49 //returned from sqlite3OsCurrentTime(). This is used for testing. |
|
50 extern "C" int sqlite3_current_time = 0; |
|
51 |
|
52 #endif//SQLITE_TEST |
|
53 |
|
54 _LIT(KCwd, ".\\"); |
|
55 |
|
56 //Used for the random numbers generation |
|
57 static inline TInt64& Seed() |
|
58 { |
|
59 static TInt64 seed = 0; |
|
60 if(seed == 0) |
|
61 { |
|
62 TTime now; |
|
63 now.UniversalTime(); |
|
64 seed = now.Int64(); |
|
65 } |
|
66 return seed; |
|
67 } |
|
68 |
|
69 /** |
|
70 Os2SqliteErr() is called at the end of many of the interface functions of the OS porting layer (wherever it is appropriate - |
|
71 TFileIo and TVfs interfaces). The purpose of this function is to identify the "out of memory" and "disk is full" errors |
|
72 reported by the used Symbian OS APIs (aOsErr parameter) and report them to SQLite as SQLITE_FULL and SQLITE_NOMEM errors. |
|
73 The KErrEof error (TFileIo::Read() can return KErrEof) is reported to SQLite as SQLITE_IOERR_SHORT_READ. The rest of failures |
|
74 are reported as the error specified in aDefaultErr parameter. |
|
75 |
|
76 @param aOsErr Symbian OS error |
|
77 @param aDefaultErr The default SQLite error that should be used if the aOsErr parameter is not one of: |
|
78 KErrNone, KErrEof, KErrNoMemory, KErrDiskFull |
|
79 @return SQLITE_OK, The OS porting layer function call has completed successfully, |
|
80 SQLITE_IOERR_SHORT_READ, The amount of the data read is less than the requested amount, |
|
81 SQLITE_IOERR_NOMEM, Out of memory, |
|
82 SQLITE_FULL, The disk is full, |
|
83 aDefaultErr, The rest of failures will be reported as aDefaultErr. |
|
84 */ |
|
85 static TInt Os2SqliteErr(TInt aOsErr, TInt aDefaultErr) |
|
86 { |
|
87 switch(aOsErr) |
|
88 { |
|
89 case KErrNone: |
|
90 return SQLITE_OK; |
|
91 case KErrEof: |
|
92 return SQLITE_IOERR_SHORT_READ; |
|
93 case KErrNoMemory: |
|
94 return SQLITE_IOERR_NOMEM; |
|
95 case KErrDiskFull: |
|
96 return SQLITE_FULL; |
|
97 default: |
|
98 #ifdef _DEBUG |
|
99 RDebug::Print(_L("SQLite3 C API, Os2SqliteErr(), err=%d\n"), aOsErr); |
|
100 #endif |
|
101 break; |
|
102 } |
|
103 return aDefaultErr; |
|
104 } |
|
105 |
|
106 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
107 ////////////////////////// TStaticFs ///////////////////////////////////////////////////////////////////////////////////////// |
|
108 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
109 |
|
110 /** |
|
111 Connects the file session used by the SQLite OS porting layer. |
|
112 Single RFs instance per process is used. |
|
113 |
|
114 @return KErrNone The operation was completed successfully, |
|
115 System-wide error code if the operation has failed. |
|
116 */ |
|
117 TInt TStaticFs::Connect() |
|
118 { |
|
119 TInt err = iFs.Connect(); |
|
120 if(err == KErrNone) |
|
121 { |
|
122 err = iFs.ShareAuto(); |
|
123 } |
|
124 if(err != KErrNone) |
|
125 { |
|
126 iFs.Close(); |
|
127 } |
|
128 return err; |
|
129 } |
|
130 |
|
131 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
132 ////////////////////////// sqlite3_mutex ///////////////////////////////////////////////////////////////////////////////////// |
|
133 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
134 |
|
135 /** |
|
136 Initializes sqlite3_mutex data members with their default values. |
|
137 */ |
|
138 sqlite3_mutex::sqlite3_mutex() : |
|
139 iRefCount(0), |
|
140 iOwnerThreadId(KMaxTUint64) |
|
141 { |
|
142 } |
|
143 |
|
144 /** |
|
145 Closes the mutex handle. |
|
146 */ |
|
147 sqlite3_mutex::~sqlite3_mutex() |
|
148 { |
|
149 iMutex.Close(); |
|
150 } |
|
151 |
|
152 /** |
|
153 Gives the calling thread an exclusive access to the SQLite resources (global variables, file handles, buffers, cache, etc.). |
|
154 The calling thread becomes a mutex owner. |
|
155 If the mutex is already locked by another thread, the calling thread will block until the other thread releases the mutex. |
|
156 The method can be called by the mutex owning thread more than once, even if the mutex is already entered. |
|
157 */ |
|
158 void sqlite3_mutex::Enter() |
|
159 { |
|
160 iMutex.Wait(); |
|
161 RThread currThread; |
|
162 iOwnerThreadId = currThread.Id(); |
|
163 ++iRefCount; |
|
164 } |
|
165 |
|
166 /** |
|
167 Unlocks the mutex. If sqlite3_mutex::Enter() was called more than once by the owning thread, then the number of |
|
168 sqlite3_mutex::Leave() calls must eventually match the number of sqlite3_mutex::Enter() calls. |
|
169 If there are thread(s) blocked on sqlite3_mutex::Enter(), after the mutex gets unlocked one of the waiting threads |
|
170 will be able to lock the mutex and get an exclusive access to the guarded resources. |
|
171 |
|
172 @panic SqliteMt 23 Negative mutex lock counter (in debug builds only) |
|
173 @panic SqliteMt 24 The mutex has been entered (locked) by a different thread than the current one (in debug builds only) |
|
174 */ |
|
175 void sqlite3_mutex::Leave() |
|
176 { |
|
177 __ASSERT_DEBUG(iRefCount > 0, User::Panic(KPanicCategory, EPanicMutexLockCounter)); |
|
178 #ifdef _DEBUG |
|
179 RThread currThread; |
|
180 __ASSERT_DEBUG(iOwnerThreadId == currThread.Id(), User::Panic(KPanicCategory, EPanicMutexOwner)); |
|
181 #endif |
|
182 --iRefCount; |
|
183 iMutex.Signal(); |
|
184 } |
|
185 |
|
186 /** |
|
187 Returns true if the mutex is already locked (entered). |
|
188 |
|
189 @return True if the mutex is locked, false otherwise |
|
190 */ |
|
191 TBool sqlite3_mutex::IsHeld() const |
|
192 { |
|
193 RThread currThread; |
|
194 return iRefCount != 0 && iOwnerThreadId == currThread.Id(); |
|
195 } |
|
196 |
|
197 /** |
|
198 Creates the mutex. |
|
199 |
|
200 @return KErrNone The operation was completed successfully, |
|
201 System-wide error code if the operation has failed. |
|
202 */ |
|
203 TInt sqlite3_mutex::Create() |
|
204 { |
|
205 return iMutex.CreateLocal(); |
|
206 } |
|
207 |
|
208 /** |
|
209 Creates new CRecursiveMutex object. |
|
210 |
|
211 @return A pointer to the created CRecursiveMutex object or NULL if the operation has failed. |
|
212 */ |
|
213 CRecursiveMutex* CRecursiveMutex::New() |
|
214 { |
|
215 CRecursiveMutex* self = new CRecursiveMutex; |
|
216 if(self) |
|
217 { |
|
218 if(self->Create() != KErrNone) |
|
219 { |
|
220 delete self; |
|
221 self = NULL; |
|
222 } |
|
223 } |
|
224 return self; |
|
225 } |
|
226 |
|
227 CRecursiveMutex::~CRecursiveMutex() |
|
228 { |
|
229 } |
|
230 |
|
231 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
232 ////////////////////////// TMutexApi //////////////////////////////////////////////////////////////////////////////////////// |
|
233 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
234 |
|
235 /** |
|
236 Initializes the mutex system. |
|
237 No-op function. |
|
238 |
|
239 @return SQLITE_OK |
|
240 */ |
|
241 int TMutexApi::Init() |
|
242 { |
|
243 SQLUTRACE_PROFILER(0); |
|
244 return SQLITE_OK; |
|
245 } |
|
246 |
|
247 /** |
|
248 Finalizes the mutex system. |
|
249 No-op function. |
|
250 |
|
251 @return SQLITE_OK |
|
252 */ |
|
253 int TMutexApi::End() |
|
254 { |
|
255 SQLUTRACE_PROFILER(0); |
|
256 return SQLITE_OK; |
|
257 } |
|
258 |
|
259 /** |
|
260 Creates a new mutex. |
|
261 If the request is for a static mutex, a pointer to already created static mutex will be returned. |
|
262 |
|
263 @param aType The mutex type: static, fast, recursive |
|
264 @return A pointer to the created mutex or NULL if the operation has failed |
|
265 */ |
|
266 sqlite3_mutex* TMutexApi::Alloc(int aType) |
|
267 { |
|
268 SQLUTRACE_PROFILER(0); |
|
269 sqlite3_mutex* mutex = NULL; |
|
270 switch(aType) |
|
271 { |
|
272 case SQLITE_MUTEX_FAST: |
|
273 case SQLITE_MUTEX_RECURSIVE: |
|
274 mutex = CRecursiveMutex::New(); |
|
275 break; |
|
276 default: |
|
277 mutex = ::StaticMutex(aType - 2); |
|
278 break; |
|
279 } |
|
280 return mutex; |
|
281 } |
|
282 |
|
283 /** |
|
284 Destroys a mutex, created previously by a call to TMutexApi::Alloc(). |
|
285 @param aMutex Pointer to the mutex object that has to be destroyed |
|
286 */ |
|
287 void TMutexApi::Free(sqlite3_mutex* aMutex) |
|
288 { |
|
289 SQLUTRACE_PROFILER(0); |
|
290 delete aMutex; |
|
291 } |
|
292 |
|
293 /** |
|
294 Locks the mutex. |
|
295 See sqlite3_mutex::Enter() for more details. |
|
296 |
|
297 @param aMutex Pointer to the mutex object |
|
298 |
|
299 @see sqlite3_mutex::Enter() |
|
300 */ |
|
301 void TMutexApi::Enter(sqlite3_mutex* aMutex) |
|
302 { |
|
303 SQLUTRACE_PROFILER(0); |
|
304 aMutex->Enter(); |
|
305 } |
|
306 |
|
307 /** |
|
308 No-op. Always returns SQLITE_BUSY. |
|
309 |
|
310 @return SQLITE_BUSY |
|
311 */ |
|
312 int TMutexApi::Try(sqlite3_mutex*) |
|
313 { |
|
314 SQLUTRACE_PROFILER(0); |
|
315 return SQLITE_BUSY; |
|
316 } |
|
317 |
|
318 /** |
|
319 Unlocks the mutex. |
|
320 See sqlite3_mutex::Leave() for more details. |
|
321 |
|
322 @param aMutex Pointer to the mutex object |
|
323 |
|
324 @see sqlite3_mutex::Leave() |
|
325 */ |
|
326 void TMutexApi::Leave(sqlite3_mutex* aMutex) |
|
327 { |
|
328 SQLUTRACE_PROFILER(0); |
|
329 aMutex->Leave(); |
|
330 } |
|
331 |
|
332 /** |
|
333 Checks whether the mutex is locked or not. |
|
334 See sqlite3_mutex::IsHeld() for more details. |
|
335 |
|
336 @param aMutex Pointer to the mutex object |
|
337 |
|
338 @return True if the mutex is locked, false otherwise |
|
339 |
|
340 @see sqlite3_mutex::IsHeld() |
|
341 */ |
|
342 int TMutexApi::Held(sqlite3_mutex* aMutex) |
|
343 { |
|
344 SQLUTRACE_PROFILER(0); |
|
345 return aMutex->IsHeld(); |
|
346 } |
|
347 |
|
348 /** |
|
349 Checks whether the mutex is locked or not. |
|
350 See sqlite3_mutex::IsHeld() for more details. |
|
351 |
|
352 @param aMutex Pointer to the mutex object |
|
353 |
|
354 @return False if the mutex is locked, true otherwise |
|
355 |
|
356 @see sqlite3_mutex::IsHeld() |
|
357 */ |
|
358 int TMutexApi::Notheld(sqlite3_mutex* aMutex) |
|
359 { |
|
360 SQLUTRACE_PROFILER(0); |
|
361 return !aMutex->IsHeld(); |
|
362 } |
|
363 |
|
364 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
365 /////////////////////////////////// SQLite init/release functions /////////////////////////////////////////////////// |
|
366 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
367 |
|
368 /** |
|
369 Initializes the OS porting layer global data. |
|
370 */ |
|
371 extern "C" SQLITE_EXPORT int sqlite3_os_init(void) |
|
372 { |
|
373 return sqlite3_vfs_register(VfsApi(), 1); |
|
374 } |
|
375 |
|
376 /** |
|
377 Destroys the OS porting layer global data. |
|
378 */ |
|
379 extern "C" SQLITE_EXPORT int sqlite3_os_end(void) |
|
380 { |
|
381 return sqlite3_vfs_unregister(VfsApi()); |
|
382 } |
|
383 |
|
384 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
385 ////////////////////////// TheFileIoApi ///////////////////////////////////////////////////////////////////////////////////// |
|
386 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
387 |
|
388 /** |
|
389 Single sqlite3_io_methods instance, which data members (function pointers) are initialized with the addresses of |
|
390 TFileIo members. |
|
391 TheFileIoApi is used by SQLite for performing OS independent file I/O. |
|
392 |
|
393 @see TFileIo |
|
394 @see TVfs |
|
395 |
|
396 @internalComponent |
|
397 */ |
|
398 const static sqlite3_io_methods TheFileIoApi = |
|
399 { |
|
400 1, //Version |
|
401 &TFileIo::Close, |
|
402 &TFileIo::Read, |
|
403 &TFileIo::Write, |
|
404 &TFileIo::Truncate, |
|
405 &TFileIo::Sync, |
|
406 &TFileIo::FileSize, |
|
407 &TFileIo::Lock, |
|
408 &TFileIo::Unlock, |
|
409 &TFileIo::CheckReservedLock, |
|
410 &TFileIo::FileControl, |
|
411 &TFileIo::SectorSize, |
|
412 &TFileIo::DeviceCharacteristics |
|
413 }; |
|
414 |
|
415 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
416 ////////////////////////// TheMutexMethods ////////////////////////////////////////////////////////////////////////////////// |
|
417 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
418 |
|
419 /** |
|
420 */ |
|
421 static sqlite3_mutex_methods TheMutexMethods = |
|
422 { |
|
423 &TMutexApi::Init, |
|
424 &TMutexApi::End, |
|
425 &TMutexApi::Alloc, |
|
426 &TMutexApi::Free, |
|
427 &TMutexApi::Enter, |
|
428 &TMutexApi::Try, |
|
429 &TMutexApi::Leave, |
|
430 &TMutexApi::Held, |
|
431 &TMutexApi::Notheld |
|
432 }; |
|
433 |
|
434 extern "C" sqlite3_mutex_methods* sqlite3DefaultMutex(void) |
|
435 { |
|
436 return &TheMutexMethods; |
|
437 }; |
|
438 |
|
439 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
440 ////////////////// UTF16<-->UTF8, conversion functions //////////////////////////////////////////////////////////// |
|
441 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
442 |
|
443 /** |
|
444 The function converts aFileName to UTF16 encoded file name, and stores the UTF16 encoded file name |
|
445 to the place pointed by aFileNameDestBuf argument. |
|
446 If the UTF16 conversion of the file name failed because the file name is too long or NULL, |
|
447 the function returns EFalse. |
|
448 |
|
449 @param aFileName Expected to point to UTF8 encoded, zero terminated string. |
|
450 Max allowed aFileName length is KMaxFileName (excluding terminating 0 character). |
|
451 @param aFileNameDestBuf Output parameter. Will hold UTF16, non-zero-terminated string. |
|
452 The max length must be at least KMaxFileName characters. |
|
453 |
|
454 @return True if the conversion has been completed successfully |
|
455 */ |
|
456 static TBool ConvertToUnicode(const char *aFileName, TDes& aFileNameDestBuf) |
|
457 { |
|
458 if(aFileName) |
|
459 { |
|
460 wchar_t* dest = reinterpret_cast <wchar_t*> (const_cast <TUint16*> (aFileNameDestBuf.Ptr())); |
|
461 TInt len = mbstowcs(dest, aFileName, KMaxFileName); |
|
462 //Check the file name length. If it is longer than KMaxFileName characters, then the file name is not valid. |
|
463 if(len > 0 && len <= KMaxFileName) |
|
464 { |
|
465 aFileNameDestBuf.SetLength(len); |
|
466 return ETrue; |
|
467 } |
|
468 } |
|
469 return EFalse; |
|
470 } |
|
471 |
|
472 /** |
|
473 The function converts aFileName to UTF8 encoded file name, and stores the UTF8 encoded file name |
|
474 to the place pointed by aFileNameDestBuf argument. |
|
475 If the UTF8 conversion of the file name failed because the file name is too long or NULL, |
|
476 the function returns EFalse. |
|
477 |
|
478 @param aFileName Expected to point to UTF16 encoded, zero terminated string. |
|
479 Max allowed aFileName length is KMaxFileName (excluding terminating 0 character). |
|
480 @param aFileNameDestBuf Output parameter. Will hold UTF8, non-zero-terminated string. |
|
481 The max length must be at least KMaxFileName characters. |
|
482 |
|
483 @return True if the conversion has been completed successfully |
|
484 */ |
|
485 static TBool ConvertFromUnicode(const TDesC& aFileName, TDes8& aFileNameDestBuf) |
|
486 { |
|
487 char* dest = reinterpret_cast <char*> (const_cast <TUint8*> (aFileNameDestBuf.Ptr())); |
|
488 const wchar_t* src = reinterpret_cast <const wchar_t*> (aFileName.Ptr()); |
|
489 TInt len = wcstombs(dest, src, KMaxFileName); |
|
490 //Check the file name length. If it is longer than KMaxFileName characters, then the file name is not valid. |
|
491 if(len > 0 && len <= KMaxFileName) |
|
492 { |
|
493 aFileNameDestBuf.SetLength(len); |
|
494 return ETrue; |
|
495 } |
|
496 return EFalse; |
|
497 } |
|
498 |
|
499 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
500 ///////////////////// TDbFile class definition /////////////////////////////////////////////////////////////////////// |
|
501 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
502 |
|
503 const TInt KFileBufSize = 8 * 1024; |
|
504 |
|
505 /** |
|
506 Initializes TDbFile data members with their default values. |
|
507 */ |
|
508 inline TDbFile::TDbFile() : |
|
509 iFileBuf(KFileBufSize), |
|
510 iFullName(NULL), |
|
511 iSharedLockByte(0), |
|
512 iLockType(SQLITE_LOCK_NONE), |
|
513 iReadOnly(EFalse), |
|
514 iSectorSize(0), |
|
515 iDeviceCharacteristics(-1) |
|
516 { |
|
517 pMethods = 0; |
|
518 } |
|
519 |
|
520 /** |
|
521 Casts the passed sqlite3_file pointer to a reference to the derived class - TDbFile&. |
|
522 All sqlite3_file pointers passed to TFileIo methods are actually pointers to TDbFile instances. |
|
523 So the cast is safe. |
|
524 |
|
525 @param aDbFile A pointer to a sqlite3_file instance |
|
526 |
|
527 @return A TDbFile reference. |
|
528 @see TFileIo |
|
529 @see TVfs |
|
530 @see TDbFile |
|
531 |
|
532 @panic Sqlite 20 In _DEBUG mode if aDbFile is NULL. |
|
533 |
|
534 @internalComponent |
|
535 */ |
|
536 static inline TDbFile& DbFile(sqlite3_file* aDbFile) |
|
537 { |
|
538 __ASSERT_DEBUG(aDbFile != 0, User::Panic(KPanicCategory, EPanicNullDbFilePtr)); |
|
539 return *(static_cast <TDbFile*> (aDbFile)); |
|
540 } |
|
541 |
|
542 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
543 ///////////////////// TFileIo class definition /////////////////////////////////////////////////////////////////////// |
|
544 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
545 |
|
546 /** |
|
547 SQLite OS porting layer API. |
|
548 |
|
549 Closes the file referred by aDbFile parameter. |
|
550 If aDbFile, which is actually a pointer to a TDbFile instance, the iFullName data member is not NULL, |
|
551 then the file will be deleted. |
|
552 |
|
553 @param aDbFile A pointer to a TDbFile instance, than contains the file handle to be closed. |
|
554 |
|
555 @return SQLITE_OK |
|
556 |
|
557 @see TDbFile |
|
558 */ |
|
559 /* static */ int TFileIo::Close(sqlite3_file* aDbFile) |
|
560 { |
|
561 SQLUTRACE_PROFILER(aDbFile); |
|
562 TDbFile& dbFile = ::DbFile(aDbFile); |
|
563 dbFile.iFileBuf.Close(); |
|
564 if(dbFile.iFullName) |
|
565 { |
|
566 (void)TStaticFs::Fs().Delete(*dbFile.iFullName); |
|
567 delete dbFile.iFullName; |
|
568 dbFile.iFullName = NULL; |
|
569 } |
|
570 OpenCounter(-1); |
|
571 return SQLITE_OK; |
|
572 } |
|
573 |
|
574 /** |
|
575 SQLite OS porting layer API. |
|
576 |
|
577 Reads from the file referred by the aDbFile parameter. |
|
578 |
|
579 @param aDbFile A pointer to a TDbFile instance, that contains the file handle to be read from. |
|
580 @param aBuf Output parameter. The data read from the file will be copied there. |
|
581 The buffer size must be at least aAmt bytes. |
|
582 @param aAmt The amount of data to be read form the file. |
|
583 @param aOffset The offset in the file where the read operation should start. |
|
584 |
|
585 @return SQLITE_FULL, The disk is full, |
|
586 SQLITE_IOERR_SHORT_READ, The amount of the data read is less than aAmt, |
|
587 SQLITE_IOERR_READ, File read error, |
|
588 SQLITE_IOERR_NOMEM, An out of memory condition has occured, |
|
589 SQLITE_OK, The operation has completed successfully. |
|
590 |
|
591 @see TDbFile |
|
592 */ |
|
593 /* static */ int TFileIo::Read(sqlite3_file* aDbFile, void* aBuf, int aAmt, sqlite3_int64 aOffset) |
|
594 { |
|
595 SQLUTRACE_PROFILER(aDbFile); |
|
596 SYMBIAN_TRACE_SQLITE_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KFileRead, aAmt, aOffset)); |
|
597 SimulateIOError(return SQLITE_IOERR_READ); |
|
598 TDbFile& dbFile = ::DbFile(aDbFile); |
|
599 TPtr8 ptr((TUint8*)aBuf, 0, aAmt); |
|
600 TInt err = dbFile.iFileBuf.Read(aOffset, ptr); |
|
601 TInt cnt = ptr.Length(); |
|
602 TInt sqliteErr = ::Os2SqliteErr(err, SQLITE_IOERR_READ); |
|
603 if(cnt != aAmt && (sqliteErr == SQLITE_OK || sqliteErr == SQLITE_IOERR_SHORT_READ)) |
|
604 { |
|
605 Mem::FillZ(static_cast <TUint8*> (aBuf) + cnt, aAmt - cnt); |
|
606 sqliteErr = SQLITE_IOERR_SHORT_READ; |
|
607 } |
|
608 return sqliteErr; |
|
609 } |
|
610 |
|
611 /** |
|
612 SQLite OS porting layer API. |
|
613 |
|
614 Writes to the file referred by the aDbFile parameter. |
|
615 "Write beyond the end of the file" operations are allowed. |
|
616 |
|
617 @param aDbFile A pointer to a TDbFile instance, that contains the file handle to be written to. |
|
618 @param aData The data to be written to the file. The buffer size must be at least aAmt bytes. |
|
619 @param aAmt The amount of data to be written to the file. |
|
620 @param aOffset The offset in the file where the write operation should start. |
|
621 |
|
622 @return SQLITE_IOERR_WRITE, the file write operation has failed or the file is read-only, |
|
623 SQLITE_FULL, The disk is full, |
|
624 SQLITE_IOERR_NOMEM, An out of memory condition has occured, |
|
625 SQLITE_OK, The operation has completed successfully. |
|
626 |
|
627 @see TDbFile |
|
628 */ |
|
629 /* static */ int TFileIo::Write(sqlite3_file* aDbFile, const void* aData, int aAmt, sqlite3_int64 aOffset) |
|
630 { |
|
631 SQLUTRACE_PROFILER(aDbFile); |
|
632 SYMBIAN_TRACE_SQLITE_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KFileWrite, aAmt, aOffset)); |
|
633 SimulateIOError(return SQLITE_IOERR_WRITE); |
|
634 SimulateDiskfullError(return SQLITE_FULL); |
|
635 TDbFile& dbFile = ::DbFile(aDbFile); |
|
636 TInt err = KErrAccessDenied; |
|
637 if(!dbFile.iReadOnly) |
|
638 { |
|
639 TPtrC8 ptr((const TUint8*)aData, aAmt); |
|
640 err = dbFile.iFileBuf.Write(aOffset, ptr); |
|
641 } |
|
642 return ::Os2SqliteErr(err, SQLITE_IOERR_WRITE); |
|
643 } |
|
644 |
|
645 /** |
|
646 SQLite OS porting layer API. |
|
647 |
|
648 Truncates the file referred by the aDbFile parameter. |
|
649 |
|
650 @param aDbFile A pointer to a TDbFile instance, that contains the file handle. |
|
651 @param aLength The new file size in bytes. |
|
652 |
|
653 @return SQLITE_IOERR_TRUNCATE, the file truncate operation has failed or the file is read-only, |
|
654 SQLITE_FULL, The disk is full, |
|
655 The file truncate operation has failed, |
|
656 SQLITE_IOERR_NOMEM, An out of memory condition has occured, |
|
657 SQLITE_OK, The operation has completed successfully. |
|
658 |
|
659 @see TDbFile |
|
660 */ |
|
661 /* static */ int TFileIo::Truncate(sqlite3_file* aDbFile, sqlite3_int64 aLength) |
|
662 { |
|
663 SQLUTRACE_PROFILER(aDbFile); |
|
664 SYMBIAN_TRACE_SQLITE_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KFileTruncate, aLength)); |
|
665 SimulateIOError(return SQLITE_IOERR_TRUNCATE); |
|
666 TDbFile& dbFile = ::DbFile(aDbFile); |
|
667 TInt err = KErrAccessDenied; |
|
668 if(!dbFile.iReadOnly) |
|
669 { |
|
670 err = dbFile.iFileBuf.SetSize(aLength); |
|
671 } |
|
672 return ::Os2SqliteErr(err, SQLITE_IOERR_TRUNCATE); |
|
673 } |
|
674 |
|
675 /** |
|
676 SQLite OS porting layer API. |
|
677 |
|
678 Flushes the file referred by the aDbFile parameter. |
|
679 |
|
680 @param aDbFile A pointer to a TDbFile instance, that contains the file handle. |
|
681 @param aFlags This parameter is not used in the production builds. It may be one of |
|
682 SQLITE_SYNC_NORMAL or SQLITE_SYNC_FULL and is used only by the TCL test suite. |
|
683 |
|
684 @return SQLITE_IOERR_FSYNC, This is a read-only file, or the file flush operation has failed, |
|
685 SQLITE_IOERR_NOMEM, An out of memory condition has occured, |
|
686 SQLITE_FULL, The disk is full, |
|
687 SQLITE_OK, The operation has completed successfully. |
|
688 |
|
689 @see TDbFile |
|
690 */ |
|
691 /* static */int TFileIo::Sync(sqlite3_file* aDbFile, int aFlags) |
|
692 { |
|
693 SQLUTRACE_PROFILER(aDbFile); |
|
694 SimulateIOError(return SQLITE_IOERR_FSYNC); |
|
695 TDbFile& dbFile = ::DbFile(aDbFile); |
|
696 #ifdef SQLITE_TEST |
|
697 if(aFlags & SQLITE_SYNC_FULL) |
|
698 { |
|
699 sqlite3_fullsync_count++; |
|
700 } |
|
701 sqlite3_sync_count++; |
|
702 #else |
|
703 aFlags = aFlags; |
|
704 #endif |
|
705 TInt err = KErrAccessDenied; |
|
706 if(!dbFile.iReadOnly) |
|
707 { |
|
708 err = dbFile.iFileBuf.Flush(); |
|
709 } |
|
710 return ::Os2SqliteErr(err, SQLITE_IOERR_FSYNC); |
|
711 } |
|
712 |
|
713 /** |
|
714 SQLite OS porting layer API. |
|
715 |
|
716 Returns the size of the file referred by the aDbFile parameter. |
|
717 |
|
718 @param aDbFile A pointer to a TDbFile instance, that contains the file handle. |
|
719 @param aSize Output parameter. If the function completes successfully, the file size will be stored there. |
|
720 |
|
721 @return SQLITE_IOERR_FSTAT, The file size operation has failed; |
|
722 SQLITE_IOERR_NOMEM, An out of memory condition has occured; |
|
723 SQLITE_OK, The operation has completed successfully. |
|
724 |
|
725 @see TDbFile |
|
726 */ |
|
727 /* static */ int TFileIo::FileSize(sqlite3_file* aDbFile, sqlite3_int64* aSize) |
|
728 { |
|
729 SQLUTRACE_PROFILER(aDbFile); |
|
730 SimulateIOError(return SQLITE_IOERR_FSTAT); |
|
731 TDbFile& dbFile = ::DbFile(aDbFile); |
|
732 TInt err = dbFile.iFileBuf.Size(*aSize); |
|
733 return ::Os2SqliteErr(err, SQLITE_IOERR_FSTAT); |
|
734 } |
|
735 |
|
736 /** |
|
737 This function is called when SQLite needs to obtain a read lock. This is done by generating a |
|
738 random file position within the first page beyond the first Gb of the file and locking a single byte there. |
|
739 There is a possible problem with that random file position, because the database file may be shared between multiple |
|
740 connections. That increases the possibility of generating the same "random" file position by different connections to the |
|
741 same file. In order to minimise that, TFileIo::GetReadLock() will generate up to 3 different file positions in a case of |
|
742 a "lock byte" failure. |
|
743 The generated file position will be stored in TDbFile::iSharedLockByte data member and will be used later for the |
|
744 unlock operation. |
|
745 |
|
746 @param aDbFile The Os porting layer file handle |
|
747 @return KErrNone The locking operation has completed successfully, |
|
748 KErrLocked The 1 byte file area that begins from the generated file position is already locked, |
|
749 Some other system-wide error codes in a case of failure. |
|
750 |
|
751 @see TFileIo::UnlockReadLock() |
|
752 */ |
|
753 /* static */TInt TFileIo::GetReadLock(TDbFile& aDbFile) |
|
754 { |
|
755 const TInt KLockTryCount = 3; |
|
756 TInt rc = KErrLocked; |
|
757 for(TInt i=0;i<KLockTryCount;++i) |
|
758 { |
|
759 TInt lock = Math::Rand(Seed()); |
|
760 //Explanation regarding how the file locking works can be found in os.h file, lines 279-335. |
|
761 //Shortly, in order to read pages from the database the calling thread must obtain a shared lock. |
|
762 //This is done locking a randomly chosen byte - iSharedLockByte. |
|
763 //The calculation of iSharedLockByte is done in a way that: |
|
764 // - All calculated iSharedLockByte fit on a single page, even if the page size is chosen to be the smallest one possible. |
|
765 // That's why the "% (SHARED_SIZE - 1)" is used in the calculation; |
|
766 // - The locked byte cannot be used for storing data. That is the reason SHARED_FIRST to be set to be a position beyond the |
|
767 // 1Gb boundary; |
|
768 TInt sharedLockByte = (lock & 0x7fffffff) % (SHARED_SIZE - 1); |
|
769 rc = aDbFile.iFileBuf.Lock(SHARED_FIRST + sharedLockByte, 1); |
|
770 if(rc == KErrNone) |
|
771 { |
|
772 aDbFile.iSharedLockByte = sharedLockByte; |
|
773 break; |
|
774 } |
|
775 } |
|
776 return rc; |
|
777 } |
|
778 |
|
779 /** |
|
780 Unlocks the file area previously locked by the GetReadLock() call. |
|
781 The beginning of the locked area with length 1 byte is stored in TDbFile::iSharedLockByte data member. |
|
782 |
|
783 @param aDbFile The Os porting layer file handle |
|
784 |
|
785 @return KErrNone The locking operation has completed successfully, |
|
786 Some other system-wide error codes in a case of failure. |
|
787 |
|
788 @see TFileIo::GetReadLock() |
|
789 */ |
|
790 /* static */TInt TFileIo::UnlockReadLock(TDbFile& aDbFile) |
|
791 { |
|
792 return aDbFile.iFileBuf.UnLock(SHARED_FIRST + aDbFile.iSharedLockByte, 1); |
|
793 } |
|
794 |
|
795 /** |
|
796 SQLite OS porting layer API. |
|
797 |
|
798 Locks the file, referred by the aDbFile parameter, with the specified lock type. |
|
799 The file lock type is stored for later use by the CheckReservedLock() call. |
|
800 |
|
801 Sometimes when requesting one lock state, additional lock states |
|
802 are inserted in between. The locking might fail on one of the later |
|
803 transitions leaving the lock state different from what it started but |
|
804 still short of its goal. The following chart shows the allowed |
|
805 transitions and the inserted intermediate states: |
|
806 |
|
807 SQLITE_LOCK_NONE -> SQLITE_LOCK_SHARED |
|
808 SQLITE_LOCK_SHARED -> SQLITE_LOCK_RESERVED |
|
809 SQLITE_LOCK_SHARED -> (SQLITE_LOCK_PENDING) -> SQLITE_LOCK_EXCLUSIVE |
|
810 SQLITE_LOCK_RESERVED -> (SQLITE_LOCK_PENDING) -> SQLITE_LOCK_EXCLUSIVE |
|
811 SQLITE_LOCK_PENDING -> SQLITE_LOCK_EXCLUSIVE |
|
812 |
|
813 @param aDbFile A pointer to a TDbFile instance, that contains the file handle. |
|
814 @param aLockType Lock type: SQLITE_LOCK_NONE, SQLITE_LOCK_SHARED, SQLITE_LOCK_RESERVED, SQLITE_LOCK_PENDING or |
|
815 SQLITE_LOCK_EXCLUSIVE. |
|
816 |
|
817 @return SQLITE_IOERR_NOMEM, An out of memory condition has occured; |
|
818 SQLITE_BUSY, The requested lock cannot be obtained; |
|
819 SQLITE_LOCK, File locking error, |
|
820 SQLITE_OK, The operation has completed successfully. |
|
821 |
|
822 @see TFileIo::CheckReservedLock() |
|
823 @see TFileIo::Unlock() |
|
824 |
|
825 @see TDbFile |
|
826 */ |
|
827 /* static */ int TFileIo::Lock(sqlite3_file* aDbFile, int aLockType) |
|
828 { |
|
829 SQLUTRACE_PROFILER(aDbFile); |
|
830 TDbFile& dbFile = ::DbFile(aDbFile); |
|
831 //If there is already a lock of this type or more restrictive on the aDbFile, then - do nothing. |
|
832 if(dbFile.iLockType >= aLockType) |
|
833 { |
|
834 return SQLITE_OK; |
|
835 } |
|
836 |
|
837 //The file flushing here must be done in order to get the file buffer object content (iFileBuf data member)) |
|
838 //synchronised with the database file content (the database file content may get modified by a different connection |
|
839 //at the same time). |
|
840 if(aLockType == SQLITE_LOCK_SHARED && !dbFile.iReadOnly) |
|
841 { |
|
842 TInt err = dbFile.iFileBuf.Flush(ETrue); |
|
843 if(err != KErrNone) |
|
844 { |
|
845 return ::Os2SqliteErr(err, SQLITE_IOERR_LOCK); |
|
846 } |
|
847 } |
|
848 |
|
849 //Make sure the locking sequence is correct |
|
850 __ASSERT_DEBUG(dbFile.iLockType != SQLITE_LOCK_NONE || aLockType == SQLITE_LOCK_SHARED, User::Panic(KPanicCategory, EPanicInvalidLock)); |
|
851 __ASSERT_DEBUG(aLockType != SQLITE_LOCK_PENDING, User::Panic(KPanicCategory, EPanicInvalidLock)); |
|
852 __ASSERT_DEBUG(aLockType != SQLITE_LOCK_RESERVED || dbFile.iLockType == SQLITE_LOCK_SHARED, User::Panic(KPanicCategory, EPanicInvalidLock)); |
|
853 |
|
854 TInt rc = SQLITE_OK; //Return code from subroutines |
|
855 TBool locked = ETrue; //Result of a file lock call (the default value means: "lock accuired") |
|
856 TInt newLockType = -1; //Set dbFile.iLockType to this value before exiting |
|
857 TBool gotPendingLock = EFalse;//True if we acquired a SQLITE_LOCK_PENDING lock this time |
|
858 |
|
859 //Lock the SQLITE_LOCK_PENDING byte if we need to acquire a SQLITE_LOCK_PENDING lock or |
|
860 //SQLITE_LOCK_SHARED lock. If we are acquiring a SQLITE_LOCK_SHARED lock, the acquisition of |
|
861 //the SQLITE_LOCK_PENDING byte is temporary. |
|
862 newLockType = dbFile.iLockType; |
|
863 if(dbFile.iLockType == SQLITE_LOCK_NONE || (aLockType == SQLITE_LOCK_EXCLUSIVE && dbFile.iLockType == SQLITE_LOCK_RESERVED)) |
|
864 { |
|
865 //Try 3 times to get the pending lock. The pending lock might be |
|
866 //held by another reader process who will release it momentarily. |
|
867 const TInt KLockTryCnt = 3; |
|
868 locked = EFalse; |
|
869 for(TInt i=0;i<KLockTryCnt && !locked;++i) |
|
870 { |
|
871 TInt err = dbFile.iFileBuf.Lock(PENDING_BYTE, 1); |
|
872 if(err != KErrNone && err != KErrLocked) |
|
873 { |
|
874 return ::Os2SqliteErr(err, SQLITE_IOERR_LOCK); |
|
875 } |
|
876 locked = (err == KErrNone); |
|
877 if(!locked) |
|
878 { |
|
879 const TInt KMs = 10; |
|
880 TVfs::Sleep(NULL, KMs * 1000); |
|
881 } |
|
882 } |
|
883 gotPendingLock = locked; |
|
884 } |
|
885 |
|
886 //Acquire a shared lock |
|
887 if(aLockType == SQLITE_LOCK_SHARED && locked) |
|
888 { |
|
889 __ASSERT_DEBUG(dbFile.iLockType == SQLITE_LOCK_NONE, User::Panic(KPanicCategory, EPanicInvalidLock)); |
|
890 TInt err = TFileIo::GetReadLock(dbFile); |
|
891 if(err != KErrNone && err != KErrLocked) |
|
892 { |
|
893 return ::Os2SqliteErr(err, SQLITE_IOERR_LOCK); |
|
894 } |
|
895 locked = (err == KErrNone); |
|
896 if(locked) |
|
897 { |
|
898 newLockType = SQLITE_LOCK_SHARED; |
|
899 } |
|
900 } |
|
901 |
|
902 //Acquire a RESERVED lock |
|
903 if(aLockType == SQLITE_LOCK_RESERVED && locked) |
|
904 { |
|
905 __ASSERT_DEBUG(dbFile.iLockType == SQLITE_LOCK_SHARED, User::Panic(KPanicCategory, EPanicInvalidLock)); |
|
906 TInt err = dbFile.iFileBuf.Lock(RESERVED_BYTE, 1); |
|
907 if(err != KErrNone && err != KErrLocked) |
|
908 { |
|
909 return ::Os2SqliteErr(err, SQLITE_IOERR_LOCK); |
|
910 } |
|
911 locked = (err == KErrNone); |
|
912 if(locked) |
|
913 { |
|
914 newLockType = SQLITE_LOCK_RESERVED; |
|
915 } |
|
916 } |
|
917 |
|
918 // Acquire a PENDING lock |
|
919 if(aLockType == SQLITE_LOCK_EXCLUSIVE && locked) |
|
920 { |
|
921 newLockType = SQLITE_LOCK_PENDING; |
|
922 gotPendingLock = EFalse; |
|
923 } |
|
924 |
|
925 //Acquire an EXCLUSIVE lock |
|
926 if(aLockType == SQLITE_LOCK_EXCLUSIVE && locked) |
|
927 { |
|
928 __ASSERT_DEBUG(dbFile.iLockType >= SQLITE_LOCK_SHARED, User::Panic(KPanicCategory, EPanicInvalidLock)); |
|
929 (void)TFileIo::UnlockReadLock(dbFile); |
|
930 TInt err = dbFile.iFileBuf.Lock(SHARED_FIRST, SHARED_SIZE); |
|
931 if(err != KErrNone && err != KErrLocked) |
|
932 { |
|
933 return ::Os2SqliteErr(err, SQLITE_IOERR_LOCK); |
|
934 } |
|
935 locked = (err == KErrNone); |
|
936 if(locked) |
|
937 { |
|
938 newLockType = SQLITE_LOCK_EXCLUSIVE; |
|
939 } |
|
940 } |
|
941 |
|
942 // If we are holding a PENDING lock that ought to be released, then |
|
943 // release it now. |
|
944 if(gotPendingLock && aLockType == SQLITE_LOCK_SHARED) |
|
945 { |
|
946 (void)dbFile.iFileBuf.UnLock(PENDING_BYTE, 1); |
|
947 } |
|
948 |
|
949 // Update the state of the lock has held in the file descriptor then |
|
950 // return the appropriate result code. |
|
951 rc = locked ? SQLITE_OK : SQLITE_BUSY; |
|
952 dbFile.iLockType = newLockType; |
|
953 return rc; |
|
954 } |
|
955 |
|
956 /** |
|
957 SQLite OS porting layer API. |
|
958 |
|
959 Lower the locking level on file descriptor id to locktype. locktype |
|
960 must be either SQLITE_LOCK_NONE or SQLITE_LOCK_SHARED. |
|
961 |
|
962 If the locking level of the file descriptor is already at or below |
|
963 the requested locking level, this routine is a no-op. |
|
964 |
|
965 It is not possible for this routine to fail if the second argument |
|
966 is SQLITE_LOCK_NONE. If the second argument is SQLITE_LOCK_SHARED then this routine |
|
967 might return SQLITE_IOERR; |
|
968 |
|
969 @param aDbFile A pointer to a TDbFile instance, that contains the file handle. |
|
970 @param aLockType Lock type: SQLITE_LOCK_NONE, SQLITE_LOCK_SHARED, SQLITE_LOCK_RESERVED, SQLITE_LOCK_PENDING or |
|
971 SQLITE_LOCK_EXCLUSIVE. |
|
972 |
|
973 @return SQLITE_OK, The operation has completed successfully, |
|
974 SQLITE_IOERR_UNLOCK, The unlock operation has failed. |
|
975 |
|
976 @see TFileIo::CheckReservedLock() |
|
977 @see TFileIo::Lock() |
|
978 |
|
979 @see TDbFile |
|
980 */ |
|
981 /* static */ int TFileIo::Unlock(sqlite3_file* aDbFile, int aLockType) |
|
982 { |
|
983 __ASSERT_DEBUG(aLockType <= SQLITE_LOCK_SHARED, User::Panic(KPanicCategory, EPanicInvalidLock)); |
|
984 |
|
985 SQLUTRACE_PROFILER(aDbFile); |
|
986 TDbFile& dbFile = ::DbFile(aDbFile); |
|
987 TInt rc = SQLITE_OK; |
|
988 TInt currLockType = dbFile.iLockType; |
|
989 |
|
990 if(currLockType >= SQLITE_LOCK_EXCLUSIVE) |
|
991 { |
|
992 (void)dbFile.iFileBuf.UnLock(SHARED_FIRST, SHARED_SIZE); |
|
993 if(aLockType == SQLITE_LOCK_SHARED) |
|
994 { |
|
995 TInt err = TFileIo::GetReadLock(dbFile); |
|
996 if(err != KErrNone && err != KErrLocked) |
|
997 { |
|
998 return ::Os2SqliteErr(err, SQLITE_IOERR_UNLOCK); |
|
999 } |
|
1000 if(err == KErrLocked) |
|
1001 { |
|
1002 //This should never happen. We should always be able to reacquire the read lock |
|
1003 rc = SQLITE_IOERR_UNLOCK; |
|
1004 } |
|
1005 } |
|
1006 } |
|
1007 if(currLockType >= SQLITE_LOCK_RESERVED) |
|
1008 { |
|
1009 (void)dbFile.iFileBuf.UnLock(RESERVED_BYTE, 1); |
|
1010 } |
|
1011 if(aLockType == SQLITE_LOCK_NONE && currLockType >= SQLITE_LOCK_SHARED) |
|
1012 { |
|
1013 (void)TFileIo::UnlockReadLock(dbFile); |
|
1014 } |
|
1015 if(currLockType>= SQLITE_LOCK_PENDING) |
|
1016 { |
|
1017 (void)dbFile.iFileBuf.UnLock(PENDING_BYTE, 1); |
|
1018 } |
|
1019 |
|
1020 dbFile.iLockType = aLockType; |
|
1021 return rc; |
|
1022 } |
|
1023 |
|
1024 /** |
|
1025 SQLite OS porting layer API. |
|
1026 |
|
1027 Checks if the file lock type is SQLITE_LOCK_RESERVED or bigger. |
|
1028 |
|
1029 @param aDbFile A pointer to a TDbFile instance, that contains the file handle. |
|
1030 @param aResOut Output parameter. It should be set to 1 if the stored lock type is bigger or equal |
|
1031 than SQLITE_LOCK_RESERVED. |
|
1032 |
|
1033 @return SQLITE_IOERR_CHECKRESERVEDLOCK, The operation has failed, |
|
1034 SQLITE_OK The operation has completed successfully. |
|
1035 |
|
1036 @see TFileIo::Lock() |
|
1037 @see TFileIo::Unlock() |
|
1038 |
|
1039 @see TDbFile |
|
1040 */ |
|
1041 /* static */ int TFileIo::CheckReservedLock(sqlite3_file* aDbFile, int *aResOut) |
|
1042 { |
|
1043 SQLUTRACE_PROFILER(aDbFile); |
|
1044 TDbFile& dbFile = ::DbFile(aDbFile); |
|
1045 TInt rc; |
|
1046 if(dbFile.iLockType >= SQLITE_LOCK_RESERVED) |
|
1047 { |
|
1048 rc = 1; |
|
1049 } |
|
1050 else |
|
1051 { |
|
1052 TInt err = dbFile.iFileBuf.Lock(RESERVED_BYTE, 1); |
|
1053 if(err != KErrNone && err != KErrLocked) |
|
1054 { |
|
1055 return ::Os2SqliteErr(err, SQLITE_IOERR_CHECKRESERVEDLOCK); |
|
1056 } |
|
1057 rc = (err == KErrNone); |
|
1058 if(rc) //non-zero rc means: the lock has been successful (there wasn't a reserved lock on this file) |
|
1059 { |
|
1060 (void)dbFile.iFileBuf.UnLock(RESERVED_BYTE, 1); |
|
1061 } |
|
1062 rc = !rc; |
|
1063 } |
|
1064 *aResOut = rc; |
|
1065 return SQLITE_OK; |
|
1066 } |
|
1067 |
|
1068 /** |
|
1069 SQLite OS porting layer API. |
|
1070 |
|
1071 Performs an aOp operation on the file referred by the aDbFile parameter. |
|
1072 Since the only supported operation at the moment is SQLITE_FCNTL_LOCKSTATE, and the current lock type is stored as |
|
1073 a data memebr of TDbFile, the function implementation has been optimised - no file I/O calls. The stored file lock type |
|
1074 is retured if the operation is SQLITE_FCNTL_LOCKSTATE. |
|
1075 |
|
1076 @param aDbFile A pointer to a TDbFile instance, that contains the file handle. |
|
1077 @param aOp File operation type. Currently only SQLITE_FCNTL_LOCKSTATE is supported. |
|
1078 @param aArg An additional input/output parameter which purpose depends on the type of the current file operation. |
|
1079 If the file operation is SQLITE_FCNTL_LOCKSTATE, then aArg is used as an output parameter, where |
|
1080 the file lock type is stored. |
|
1081 |
|
1082 @return SQLITE_ERROR, Non-supported operation, |
|
1083 SQLITE_OK, The operation has completed successfully. |
|
1084 |
|
1085 @see TDbFile |
|
1086 */ |
|
1087 /* static */ int TFileIo::FileControl(sqlite3_file* aDbFile, int aOp, void* aArg) |
|
1088 { |
|
1089 SQLUTRACE_PROFILER(aDbFile); |
|
1090 TDbFile& dbFile = ::DbFile(aDbFile); |
|
1091 SYMBIAN_TRACE_SQLITE_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KFileFileCtr, aOp, dbFile.iFullName)); |
|
1092 TInt err = KErrNone; |
|
1093 switch(aOp) |
|
1094 { |
|
1095 case SQLITE_FCNTL_LOCKSTATE: |
|
1096 *(int*)aArg = dbFile.iLockType; |
|
1097 break; |
|
1098 default: |
|
1099 err = KErrArgument; |
|
1100 break; |
|
1101 } |
|
1102 return err == KErrNone ? SQLITE_OK : SQLITE_ERROR; |
|
1103 } |
|
1104 |
|
1105 /** |
|
1106 SQLite OS porting layer API. |
|
1107 |
|
1108 Retrieves the sector size of the media of the file referred by the aDbFile parameter. |
|
1109 Since the sector size never changes till the file is open, the function has been optimised - no file I/O calls. |
|
1110 The sector size is retrieved during the TVfs::Open() call and stored in TDbFile::iSectorSize. The SectorSize() |
|
1111 call returns the value of TDbFile::iSectorSize. |
|
1112 |
|
1113 @param aDbFile A pointer to a TDbFile instance, that contains the file handle. |
|
1114 |
|
1115 @return The sector size. |
|
1116 |
|
1117 @panic Sqlite 19 In _DEBUG mode - TDbFile::iSectorSize is negative or 0 . |
|
1118 |
|
1119 @see TDbFile |
|
1120 @see TVfs::Open() |
|
1121 */ |
|
1122 /* static */ int TFileIo::SectorSize(sqlite3_file* aDbFile) |
|
1123 { |
|
1124 SQLUTRACE_PROFILER(aDbFile); |
|
1125 TDbFile& dbFile = ::DbFile(aDbFile); |
|
1126 __ASSERT_DEBUG(dbFile.iSectorSize > 0, User::Panic(KPanicCategory, EPanicInternalError)); |
|
1127 if(dbFile.iSectorSize > 0) |
|
1128 { |
|
1129 return dbFile.iSectorSize; |
|
1130 } |
|
1131 return SQLITE_DEFAULT_SECTOR_SIZE; |
|
1132 } |
|
1133 |
|
1134 /** |
|
1135 SQLite OS porting layer API. |
|
1136 |
|
1137 Retrieves the device characteristics of the device of the file referred by the aDbFile parameter. |
|
1138 Since the device characteristics never change till the file is open, the function has been optimised - no file I/O calls. |
|
1139 The device characteristics are retrieved during the TVfs::Open() call and stored in TDbFile::iDeviceCharacteristics. |
|
1140 The DeviceCharacteristics() call returns the value of TDbFile::iDeviceCharacteristics. |
|
1141 |
|
1142 @param aDbFile A pointer to a TDbFile instance, that contains the file handle. |
|
1143 |
|
1144 @return A bit set containing the device characteristics. |
|
1145 |
|
1146 @panic Sqlite 19 In _DEBUG mode - TDbFile::iDeviceCharacteristics is negative or 0 . |
|
1147 |
|
1148 @see TDbFile |
|
1149 @see TVfs::Open() |
|
1150 */ |
|
1151 /* static */ int TFileIo::DeviceCharacteristics(sqlite3_file* aDbFile) |
|
1152 { |
|
1153 SQLUTRACE_PROFILER(aDbFile); |
|
1154 TDbFile& dbFile = ::DbFile(aDbFile); |
|
1155 __ASSERT_DEBUG(dbFile.iDeviceCharacteristics >= 0, User::Panic(KPanicCategory, EPanicInternalError)); |
|
1156 if(dbFile.iDeviceCharacteristics >= 0) |
|
1157 { |
|
1158 return dbFile.iDeviceCharacteristics; |
|
1159 } |
|
1160 return 0; |
|
1161 } |
|
1162 |
|
1163 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
1164 /////////////////////////////////// TVfs class definition /////////////////////////////////////////////////////////// |
|
1165 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
1166 |
|
1167 /** |
|
1168 Collects information about the drive referred by the aDriveNo parameter. |
|
1169 |
|
1170 @param aFs RFs instance. |
|
1171 @param aDriveNo The drive about which an information will be collected. |
|
1172 @param aVolumeInfo Output parameter. A reference to a TVolumeIOParamInfo object where the collected information will be stored. |
|
1173 |
|
1174 @return KErrNone, The operation has completed succesfully; |
|
1175 KErrNoMemory, Out of memory condition has occured; |
|
1176 Note that other system-wide error codes may also be returned. |
|
1177 |
|
1178 @see TVfs::Open() |
|
1179 */ |
|
1180 /* static */ inline TInt TVfs::DoGetVolumeIoParamInfo(RFs& aFs, TInt aDriveNo, TVolumeIOParamInfo& aVolumeInfo) |
|
1181 { |
|
1182 return aFs.VolumeIOParam(aDriveNo, aVolumeInfo); |
|
1183 } |
|
1184 |
|
1185 /** |
|
1186 Retrieves and returns in a bit set the device characteristics. |
|
1187 |
|
1188 @param aDriveInfo A TDriveInfo reference from which the device characteristics will be extracted. |
|
1189 @param aVolumeInfo A TVolumeIOParamInfo reference from which the device characteristics will be extracted. |
|
1190 |
|
1191 @return A bit set containing the device characteristics: |
|
1192 SQLITE_IOCAP_SAFE_APPEND, SQLITE_IOCAP_ATOMIC, the atomic block size. |
|
1193 |
|
1194 @see TVfs::DoGetDriveInfo(); |
|
1195 @see TVfs::DoGetVolumeIoParamInfo(); |
|
1196 @see TVfs::Open() |
|
1197 */ |
|
1198 /* static */ TInt TVfs::DoGetDeviceCharacteristics(const TDriveInfo& aDriveInfo, const TVolumeIOParamInfo& aVolumeInfo) |
|
1199 { |
|
1200 TInt deviceCharacteristics = 0; |
|
1201 if(aDriveInfo.iDriveAtt & (KDriveAttLocal | KDriveAttInternal)) |
|
1202 { |
|
1203 deviceCharacteristics |= SQLITE_IOCAP_SAFE_APPEND;//Data written first, file size updated second |
|
1204 } |
|
1205 if(aDriveInfo.iDriveAtt & KDriveAttTransaction) |
|
1206 { |
|
1207 deviceCharacteristics |= SQLITE_IOCAP_ATOMIC; |
|
1208 } |
|
1209 if(aVolumeInfo.iBlockSize >= SQLITE_DEFAULT_SECTOR_SIZE && (aVolumeInfo.iBlockSize & (aVolumeInfo.iBlockSize - 1)) == 0) |
|
1210 { |
|
1211 switch(aVolumeInfo.iBlockSize) |
|
1212 { |
|
1213 case 512: |
|
1214 deviceCharacteristics |= SQLITE_IOCAP_ATOMIC512; |
|
1215 break; |
|
1216 case 1024: |
|
1217 deviceCharacteristics |= SQLITE_IOCAP_ATOMIC1K; |
|
1218 break; |
|
1219 case 2048: |
|
1220 deviceCharacteristics |= SQLITE_IOCAP_ATOMIC2K; |
|
1221 break; |
|
1222 case 4096: |
|
1223 deviceCharacteristics |= SQLITE_IOCAP_ATOMIC4K; |
|
1224 break; |
|
1225 case 8192: |
|
1226 deviceCharacteristics |= SQLITE_IOCAP_ATOMIC8K; |
|
1227 break; |
|
1228 case 16384: |
|
1229 deviceCharacteristics |= SQLITE_IOCAP_ATOMIC16K; |
|
1230 break; |
|
1231 case 32768: |
|
1232 deviceCharacteristics |= SQLITE_IOCAP_ATOMIC32K; |
|
1233 break; |
|
1234 case 65536: |
|
1235 deviceCharacteristics |= SQLITE_IOCAP_ATOMIC64K; |
|
1236 break; |
|
1237 default: |
|
1238 //Do nothing. deviceCharacteristics was initialized with 0 at the beginning of the function body. |
|
1239 break; |
|
1240 } |
|
1241 } |
|
1242 return deviceCharacteristics; |
|
1243 } |
|
1244 |
|
1245 /** |
|
1246 Retrieves and returns the sector size of the drive referred by the aDriveInfo parameter. |
|
1247 The sector size must be a power of two. |
|
1248 The sector size is extracted only if aDriveInfo refers to a removable device, otherwise the |
|
1249 SQLITE_DEFAULT_SECTOR_SIZE value (512 bytes) will be used as a sector size. |
|
1250 |
|
1251 @param aDriveInfo A TDriveInfo reference. |
|
1252 @param aVolumeInfo A TVolumeIOParamInfo reference. |
|
1253 |
|
1254 @return The sector size of the drive referred by the aDriveInfo parameter. |
|
1255 |
|
1256 @panic Sqlite 19 In _DEBUG mode - The sector size is negative, zero or is not a power of two. |
|
1257 |
|
1258 @see TVfs::Open() |
|
1259 */ |
|
1260 /* static */ TInt TVfs::DoGetSectorSize(const TDriveInfo& aDriveInfo, const TVolumeIOParamInfo& aVolumeInfo) |
|
1261 { |
|
1262 //Initialize the sectorSize variable only if: |
|
1263 // - aDriveInfo refers to a removable drive |
|
1264 // - aVolumeInfo.iBlockSize > SQLITE_DEFAULT_SECTOR_SIZE; |
|
1265 // - aVolumeInfo.iBlockSize is power of 2; |
|
1266 TInt sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; |
|
1267 if(aDriveInfo.iDriveAtt & KDriveAttRemovable) |
|
1268 { |
|
1269 if(aVolumeInfo.iBlockSize > SQLITE_DEFAULT_SECTOR_SIZE && (aVolumeInfo.iBlockSize & (aVolumeInfo.iBlockSize - 1)) == 0) |
|
1270 { |
|
1271 sectorSize = aVolumeInfo.iBlockSize; |
|
1272 } |
|
1273 } |
|
1274 __ASSERT_DEBUG(sectorSize > 0 && (sectorSize & (sectorSize - 1)) == 0, User::Panic(KPanicCategory, EPanicInternalError)); |
|
1275 return sectorSize; |
|
1276 } |
|
1277 |
|
1278 /** |
|
1279 Retrieves in a bit set the device characteristics of the device of the file referred by the aDbFile parameter. |
|
1280 Retrieves the sector size of the drive of the file referred by the aDbFile parameter. |
|
1281 The sector size and the device characteristics will be stored in iSectorSize and iDeviceCharacteristics TDbFile data members. |
|
1282 The stored values will be used later by TFileIo::DeviceCharacteristics() and TFileIo::SectorSize(). |
|
1283 |
|
1284 @param aDbFile Input/Output parameter. A TDriveInfo reference. The collected information will be stored in TDbDrive |
|
1285 data members. |
|
1286 @param aRecReadBufSize Output parameter. The recommended buffer size for optimised reading performance. |
|
1287 |
|
1288 @return KErrNone, The operation has completed succesfully; |
|
1289 Note that other system-wide error codes may also be returned. |
|
1290 |
|
1291 @panic Sqlite 19 In _DEBUG mode - TDbFile::iSectorSize has been already initialized. |
|
1292 @panic Sqlite 19 In _DEBUG mode - TDbFile::iDeviceCharacteristics has been already initialized. |
|
1293 |
|
1294 @see TVfs::DoGetDeviceCharacteristics(); |
|
1295 @see TVfs::DoGetSectorSize(); |
|
1296 @see TVfs::Open() |
|
1297 @see TDbFile |
|
1298 @see TFileIo::DeviceCharacteristics() |
|
1299 @see TFileIo::SectorSize() |
|
1300 */ |
|
1301 /* static */ TInt TVfs::DoGetDeviceCharacteristicsAndSectorSize(TDbFile& aDbFile, TInt& aRecReadBufSize) |
|
1302 { |
|
1303 __ASSERT_DEBUG(aDbFile.iDeviceCharacteristics < 0, User::Panic(KPanicCategory, EPanicInternalError)); |
|
1304 __ASSERT_DEBUG(aDbFile.iSectorSize <= 0, User::Panic(KPanicCategory, EPanicInternalError)); |
|
1305 TInt driveNo; |
|
1306 TDriveInfo driveInfo; |
|
1307 TInt err = aDbFile.iFileBuf.Drive(driveNo, driveInfo); |
|
1308 if(err != KErrNone) |
|
1309 { |
|
1310 return err; |
|
1311 } |
|
1312 TVolumeIOParamInfo volumeInfo; |
|
1313 err = TVfs::DoGetVolumeIoParamInfo(TStaticFs::Fs(), driveNo, volumeInfo); |
|
1314 if(err != KErrNone) |
|
1315 { |
|
1316 return err; |
|
1317 } |
|
1318 aDbFile.iDeviceCharacteristics = TVfs::DoGetDeviceCharacteristics(driveInfo, volumeInfo); |
|
1319 aDbFile.iSectorSize = TVfs::DoGetSectorSize(driveInfo, volumeInfo); |
|
1320 aRecReadBufSize = volumeInfo.iRecReadBufSize; |
|
1321 return KErrNone; |
|
1322 } |
|
1323 |
|
1324 //Creates a temporary file. The file location will be the application's session path. |
|
1325 //If the session path does not exist, then the function will create the session path. |
|
1326 static TInt CreateTempFile(TDbFile& aDbFile, TFileName& aFileNameOut, TInt aFileMode) |
|
1327 { |
|
1328 TFileName sessionPath; |
|
1329 TInt err = TStaticFs::Fs().SessionPath(sessionPath); |
|
1330 if(err == KErrNone) |
|
1331 { |
|
1332 err = aDbFile.iFileBuf.Temp(TStaticFs::Fs(), sessionPath, aFileNameOut, aFileMode); |
|
1333 if(err == KErrPathNotFound) |
|
1334 { |
|
1335 err = TStaticFs::Fs().MkDirAll(sessionPath); |
|
1336 if(err == KErrNone) |
|
1337 { |
|
1338 err = aDbFile.iFileBuf.Temp(TStaticFs::Fs(), sessionPath, aFileNameOut, aFileMode); |
|
1339 } |
|
1340 } |
|
1341 if(err == KErrNone) |
|
1342 { |
|
1343 aDbFile.iFullName = aFileNameOut.Alloc(); |
|
1344 if(!aDbFile.iFullName) |
|
1345 { |
|
1346 aDbFile.iFileBuf.Close(); |
|
1347 (void)TStaticFs::Fs().Delete(aFileNameOut); |
|
1348 err = KErrNoMemory; |
|
1349 } |
|
1350 } |
|
1351 } |
|
1352 return err; |
|
1353 } |
|
1354 |
|
1355 /** |
|
1356 SQLite OS porting layer API. |
|
1357 |
|
1358 Opens or creates a file which name is in the aFileName parameter. |
|
1359 If the function succeeds, the file handle and other related information will be stored in the place pointed by the |
|
1360 aDbFile parameter, a memory block of sizeof(TDbFile) size for which is allocated by the caller. |
|
1361 The function will also retrieve the sector size and the device characteristics and store them in aDbFile, |
|
1362 which is actually a TDbFile pointer, for later use. |
|
1363 |
|
1364 @param aFileName Zero-terminated, UTF8 encoded file name. |
|
1365 If aFileName is NULL then a temporary file is created. |
|
1366 @param aDbFile Output parameter. The file handle and other related information will be stored there. |
|
1367 @param aFlags "Open/Create" input flags: |
|
1368 SQLITE_OPEN_DELETEONCLOSE, |
|
1369 SQLITE_OPEN_READWRITE, |
|
1370 SQLITE_OPEN_EXCLUSIVE, |
|
1371 SQLITE_OPEN_CREATE |
|
1372 @param aOutFlags "Open/Create" output flags: |
|
1373 SQLITE_OPEN_READWRITE, |
|
1374 SQLITE_OPEN_READONLY |
|
1375 |
|
1376 @return SQLITE_CANTOPEN, The aFileName parameter cannot be converted to UTF16. |
|
1377 Any other file I/O error will also be reported as SQLITE_CANTOPEN; |
|
1378 SQLITE_IOERR_NOMEM, An out of memory condition has occured; |
|
1379 SQLITE_OK, The operation has completed successfully. |
|
1380 |
|
1381 @see TDbFile |
|
1382 */ |
|
1383 /* static */ int TVfs::Open(sqlite3_vfs* aVfs, const char* aFileName, sqlite3_file* aDbFile, int aFlags, int* aOutFlags) |
|
1384 { |
|
1385 SQLUTRACE_PROFILER(aVfs); |
|
1386 TFileName fname; |
|
1387 if(aFileName && !::ConvertToUnicode(aFileName, fname)) |
|
1388 { |
|
1389 return SQLITE_CANTOPEN; |
|
1390 } |
|
1391 SYMBIAN_TRACE_SQLITE_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KFileOpen, aDbFile, &fname)); |
|
1392 new (aDbFile) TDbFile; |
|
1393 TDbFile& dbFile = ::DbFile(aDbFile); |
|
1394 if(aFileName && (aFlags & SQLITE_OPEN_DELETEONCLOSE)) |
|
1395 { |
|
1396 dbFile.iFullName = fname.Alloc(); |
|
1397 if(!dbFile.iFullName) |
|
1398 { |
|
1399 return SQLITE_IOERR_NOMEM; |
|
1400 } |
|
1401 } |
|
1402 TInt recReadBufSize = -1; |
|
1403 TInt err = KErrNone; |
|
1404 TInt fmode = EFileRead; |
|
1405 if(aFlags & SQLITE_OPEN_READWRITE) |
|
1406 { |
|
1407 fmode |= EFileWrite; |
|
1408 } |
|
1409 //SQLite TCL tests expect the journal file to be open in shared mode. |
|
1410 if(aFlags & SQLITE_OPEN_EXCLUSIVE && !(aFlags & SQLITE_OPEN_MAIN_JOURNAL)) |
|
1411 { |
|
1412 fmode |= EFileShareExclusive; |
|
1413 } |
|
1414 else |
|
1415 { |
|
1416 fmode |= (fmode & EFileWrite) ? EFileShareAny : EFileShareReadersOnly; |
|
1417 } |
|
1418 if(!aFileName) |
|
1419 {//Create temporary file |
|
1420 err = ::CreateTempFile(dbFile, fname, fmode); |
|
1421 } |
|
1422 else |
|
1423 { |
|
1424 err = KErrGeneral;//The error has to be set here, because, there is case where none of the file create/open operations will be executed |
|
1425 if(aFlags & SQLITE_OPEN_CREATE) |
|
1426 { |
|
1427 err = dbFile.iFileBuf.Create(TStaticFs::Fs(), fname, fmode); |
|
1428 } |
|
1429 if(err != KErrNone && err != KErrNoMemory) |
|
1430 { |
|
1431 err = dbFile.iFileBuf.Open(TStaticFs::Fs(), fname, fmode); |
|
1432 } |
|
1433 if((err != KErrNone && err != KErrNoMemory) && (aFlags & SQLITE_OPEN_READWRITE)) |
|
1434 { |
|
1435 aFlags &= ~SQLITE_OPEN_READWRITE; |
|
1436 aFlags |= SQLITE_OPEN_READONLY; |
|
1437 fmode &= ~EFileWrite; |
|
1438 err = dbFile.iFileBuf.Open(TStaticFs::Fs(), fname, fmode); |
|
1439 } |
|
1440 } |
|
1441 if(err == KErrNone) |
|
1442 { |
|
1443 err = TVfs::DoGetDeviceCharacteristicsAndSectorSize(dbFile, recReadBufSize); |
|
1444 } |
|
1445 if(err != KErrNone) |
|
1446 { |
|
1447 dbFile.iFileBuf.Close(); |
|
1448 delete dbFile.iFullName; |
|
1449 dbFile.iFullName = NULL; |
|
1450 } |
|
1451 else |
|
1452 { |
|
1453 dbFile.pMethods = &TheFileIoApi; |
|
1454 dbFile.iReadOnly = !(aFlags & SQLITE_OPEN_READWRITE); |
|
1455 if(aOutFlags) |
|
1456 { |
|
1457 *aOutFlags = dbFile.iReadOnly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE; |
|
1458 } |
|
1459 (void)dbFile.iFileBuf.SetReadAheadSize(dbFile.iSectorSize, recReadBufSize); |
|
1460 OpenCounter(+1); |
|
1461 } |
|
1462 return ::Os2SqliteErr(err, SQLITE_CANTOPEN); |
|
1463 } |
|
1464 |
|
1465 /** |
|
1466 SQLite OS porting layer API. |
|
1467 |
|
1468 Deletes a file which name is in the aFileName parameter. |
|
1469 |
|
1470 @param aFileName Zero-terminated, UTF8 encoded file name. |
|
1471 |
|
1472 @return SQLITE_ERROR, The aFileName parameter cannot be converted to UTF16. |
|
1473 The file name refers to a private secure database; |
|
1474 SQLITE_IOERR_NOMEM, An out of memory condition has occured; |
|
1475 SQLITE_IOERR_DELETE,The delete file operation has failed; |
|
1476 SQLITE_OK, The operation has completed successfully. |
|
1477 */ |
|
1478 /* static */ int TVfs::Delete(sqlite3_vfs* aVfs, const char* aFileName, int /*aSyncDir*/) |
|
1479 { |
|
1480 SQLUTRACE_PROFILER(aVfs); |
|
1481 SimulateIOError(return SQLITE_IOERR_DELETE); |
|
1482 TFileName fname; |
|
1483 if(!::ConvertToUnicode(aFileName, fname)) |
|
1484 { |
|
1485 return SQLITE_ERROR; |
|
1486 } |
|
1487 SYMBIAN_TRACE_SQLITE_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KFileName, &fname)); |
|
1488 TInt err = TStaticFs::Fs().Delete(fname); |
|
1489 return ::Os2SqliteErr(err, SQLITE_IOERR_DELETE); |
|
1490 } |
|
1491 |
|
1492 /** |
|
1493 SQLite OS porting layer API. |
|
1494 |
|
1495 Retrieves an information about a file which name is in the aFileName parameter. |
|
1496 The requested information type can be: does the file exist, is the file read-only or read/write. |
|
1497 |
|
1498 @param aFileName Zero-terminated, UTF8 encoded file name. |
|
1499 @param aFlags This parameter can be one of: SQLITE_ACCESS_READ, SQLITE_ACCESS_EXISTS or SQLITE_ACCESS_READWRITE. |
|
1500 @param aResOut Output parameter, set to 1 if the tested condition is true, 0 otherwise. |
|
1501 |
|
1502 @return SQLITE_OK, The call has completed successfully, |
|
1503 SQLITE_IOERR_NOMEM, An out of memory conditon has occured, |
|
1504 SQLITE_IOERR_ACCESS,File I/O error; |
|
1505 */ |
|
1506 /* static */ int TVfs::Access(sqlite3_vfs* aVfs, const char* aFileName, int aFlags, int* aResOut) |
|
1507 { |
|
1508 SQLUTRACE_PROFILER(aVfs); |
|
1509 TFileName fname; |
|
1510 if(!::ConvertToUnicode(aFileName, fname)) |
|
1511 { |
|
1512 return SQLITE_IOERR_ACCESS; |
|
1513 } |
|
1514 SYMBIAN_TRACE_SQLITE_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KFileName, &fname)); |
|
1515 TEntry entry; |
|
1516 TInt err = TStaticFs::Fs().Entry(fname, entry); |
|
1517 if(aFlags == SQLITE_ACCESS_EXISTS && err == KErrNotFound) |
|
1518 { |
|
1519 *aResOut = 0; |
|
1520 return SQLITE_OK; |
|
1521 } |
|
1522 if(err != KErrNone) |
|
1523 { |
|
1524 return err == KErrNoMemory ? SQLITE_IOERR_NOMEM : SQLITE_IOERR_ACCESS; |
|
1525 } |
|
1526 *aResOut = 0; |
|
1527 switch(aFlags) |
|
1528 { |
|
1529 case SQLITE_ACCESS_READ: |
|
1530 *aResOut = entry.IsReadOnly(); |
|
1531 break; |
|
1532 case SQLITE_ACCESS_EXISTS: |
|
1533 *aResOut = 1; |
|
1534 break; |
|
1535 case SQLITE_ACCESS_READWRITE: |
|
1536 *aResOut = !entry.IsReadOnly(); |
|
1537 break; |
|
1538 default: |
|
1539 break; |
|
1540 } |
|
1541 return SQLITE_OK; |
|
1542 } |
|
1543 |
|
1544 /** |
|
1545 SQLite OS porting layer API. |
|
1546 |
|
1547 Accepts UTF8 encoded, zero-terminated file as an input argument in the aRelative parameter |
|
1548 and constructs the full file path in the aBuf output parameter. |
|
1549 |
|
1550 If the format of aRelative argument is <[SID]FileName.[EXT]>, then the database file name will be |
|
1551 treated as a name of a secure database file which has to be created/opened in the server's private |
|
1552 directory on the system drive. |
|
1553 |
|
1554 If the format of aRelative argument is <Drive:[SID]FileName.[EXT]>, then the database file name |
|
1555 will be treated as a name of a secure database file which has to be created/opened in the server's |
|
1556 private directory on <Drive:> drive. |
|
1557 |
|
1558 If the format of aRelative argument is <Drive:\Path\FileName.[EXT]>, then the database file name |
|
1559 will be treated as a name of a non-secure database file in <Drive:\Path\> directory. |
|
1560 If aRelative contains file handles, then it will be treated as a name of a file belonging to server's |
|
1561 private data cage. |
|
1562 |
|
1563 @param aRelative The input file name, zero-terminated, UTF8 encoded. |
|
1564 @param aBufLen The output buffer length. |
|
1565 @param aBuf Output buffer for the constructed full file name path. The allocated buffer length must be at least aBufLen bytes. |
|
1566 |
|
1567 @return SQLITE_ERROR, The aRelative parameter is NULL or cannot be converted to UTF16; |
|
1568 SQLITE_OK The operation has completed successfully. |
|
1569 */ |
|
1570 /* static */ int TVfs::FullPathName(sqlite3_vfs* aVfs, const char* aRelative, int aBufLen, char* aBuf) |
|
1571 { |
|
1572 SQLUTRACE_PROFILER(aVfs); |
|
1573 if(!aRelative) //NULL argument |
|
1574 { |
|
1575 return SQLITE_ERROR; |
|
1576 } |
|
1577 //Convert the received file name to UTF16 |
|
1578 TBuf<KMaxFileName + 1> fname; |
|
1579 if(!::ConvertToUnicode(aRelative, fname)) |
|
1580 { |
|
1581 return SQLITE_ERROR; |
|
1582 } |
|
1583 SYMBIAN_TRACE_SQLITE_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KFileName, &fname)); |
|
1584 //Search if the file name begins with ".\" - current directory |
|
1585 if(fname.Find(KCwd) == 0) |
|
1586 { |
|
1587 fname.Delete(0, KCwd().Length()); |
|
1588 } |
|
1589 fname.Append(TChar(0));//Zero-terminate the converted file name |
|
1590 TFileName defaultPath; |
|
1591 TInt err = TStaticFs::Fs().SessionPath(defaultPath); |
|
1592 if(err != KErrNone) |
|
1593 { |
|
1594 return SQLITE_ERROR; |
|
1595 } |
|
1596 TParse parse; |
|
1597 (void)parse.Set(fname, &defaultPath, 0);//If fname does not have a path, defaultPath will be used |
|
1598 TPtr8 dest8(reinterpret_cast <TUint8*> (aBuf), aBufLen); |
|
1599 if(!::ConvertFromUnicode(parse.FullName(), dest8)) |
|
1600 { |
|
1601 return SQLITE_ERROR; |
|
1602 } |
|
1603 return SQLITE_OK; |
|
1604 } |
|
1605 |
|
1606 /** |
|
1607 SQLite OS porting layer API. |
|
1608 |
|
1609 Generates a set of random numbers and stores them in the aBuf output parameter. |
|
1610 |
|
1611 @param aBufLen The output buffer length. |
|
1612 @param aBuf Output buffer for the generated random numbers. The allocated buffer length must be at least aBufLen bytes. |
|
1613 |
|
1614 @return The length of the used part of the output buffer. |
|
1615 */ |
|
1616 /* static */ int TVfs::Randomness(sqlite3_vfs* aVfs, int aBufLen, char* aBuf) |
|
1617 { |
|
1618 SQLUTRACE_PROFILER(aVfs); |
|
1619 const TInt KRandIterations = aBufLen / sizeof(int); |
|
1620 for(TInt i=0;i<KRandIterations;++i) |
|
1621 { |
|
1622 TInt val = Math::Rand(Seed()); |
|
1623 Mem::Copy(&aBuf[i * sizeof(int)], &val, sizeof(val)); |
|
1624 } |
|
1625 return KRandIterations * sizeof(int); |
|
1626 } |
|
1627 |
|
1628 /** |
|
1629 SQLite OS porting layer API. |
|
1630 |
|
1631 Sleeps for aMicrosec microseconds. |
|
1632 |
|
1633 @param aMicrosec The sleep interval in microseconds. |
|
1634 |
|
1635 @return The aMicrosec value. |
|
1636 */ |
|
1637 /* static */ int TVfs::Sleep(sqlite3_vfs* aVfs, int aMicrosec) |
|
1638 { |
|
1639 SQLUTRACE_PROFILER(aVfs); |
|
1640 User::AfterHighRes(TTimeIntervalMicroSeconds32(aMicrosec)); |
|
1641 return aMicrosec; |
|
1642 } |
|
1643 |
|
1644 /** |
|
1645 SQLite OS porting layer API. |
|
1646 |
|
1647 Retrieves the current date and time. |
|
1648 |
|
1649 @param aNow Output parameter, where the data and time value will be stored. |
|
1650 SQLite processes all times and dates as Julian Day numbers and |
|
1651 aNow parameter will contain the julian date and time. |
|
1652 |
|
1653 @return 0. |
|
1654 */ |
|
1655 /* static */ int TVfs::CurrentTime(sqlite3_vfs* aVfs, double* aNow) |
|
1656 { |
|
1657 SQLUTRACE_PROFILER(aVfs); |
|
1658 TTime now; |
|
1659 now.UniversalTime(); |
|
1660 TDateTime date = now.DateTime(); |
|
1661 TInt year = date.Year(); |
|
1662 TInt month = date.Month() + 1; |
|
1663 TInt day = date.Day() + 1; |
|
1664 |
|
1665 //Calculate the Julian days |
|
1666 TInt jd = day - 32076 + |
|
1667 1461*(year + 4800 + (month - 14)/12)/4 + |
|
1668 367*(month - 2 - (month - 14)/12*12)/12 - |
|
1669 3*((year + 4900 + (month - 14)/12)/100)/4; |
|
1670 |
|
1671 *aNow = jd; |
|
1672 |
|
1673 // Add the fractional hours, mins and seconds |
|
1674 *aNow += (date.Hour() + 12.0) / 24.0; |
|
1675 *aNow += date.Minute() / 1440.0; |
|
1676 *aNow += date.Second() / 86400.0; |
|
1677 |
|
1678 #ifdef SQLITE_TEST |
|
1679 if( sqlite3_current_time ) |
|
1680 { |
|
1681 *aNow = sqlite3_current_time / 86400.0 + 2440587.5; |
|
1682 } |
|
1683 #endif |
|
1684 return 0; |
|
1685 } |
|
1686 |
|
1687 /** |
|
1688 SQLite OS porting layer API. |
|
1689 |
|
1690 Retrieves a text description of the last OS error. |
|
1691 Note: the method has a default "no-op" implementation at the moment. |
|
1692 |
|
1693 @return 0. |
|
1694 */ |
|
1695 /* static */int TVfs::GetLastError(sqlite3_vfs* aVfs, int /*aBufLen*/, char* /*aBuf*/) |
|
1696 { |
|
1697 SQLUTRACE_PROFILER(aVfs); |
|
1698 return 0; |
|
1699 } |
|
1700 |
|
1701 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
1702 |
|
1703 #endif//SQLITE_OS_SYMBIAN |