1 /*
2 ** 2008 Jan 22
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 modified the OS layer in order to simulate
14 ** different device types (by overriding the return values of the
15 ** xDeviceCharacteristics() and xSectorSize() methods).
16 */
17 #if SQLITE_TEST /* This file is used for testing only */
18
19 #include "sqlite3.h"
20 #include "sqliteInt.h"
21
22 /*
23 ** Maximum pathname length supported by the devsym backend.
24 */
25 #define DEVSYM_MAX_PATHNAME 512
26
27 /*
28 ** Name used to identify this VFS.
29 */
30 #define DEVSYM_VFS_NAME "devsym"
31 #define WRITECRASH_NAME "writecrash"
32
33 typedef struct devsym_file devsym_file;
34 struct devsym_file {
35 sqlite3_file base;
36 sqlite3_file *pReal;
37 };
38
39 /*
40 ** Method declarations for devsym_file.
41 */
42 static int devsymClose(sqlite3_file*);
43 static int devsymRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
44 static int devsymWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
45 static int devsymTruncate(sqlite3_file*, sqlite3_int64 size);
46 static int devsymSync(sqlite3_file*, int flags);
47 static int devsymFileSize(sqlite3_file*, sqlite3_int64 *pSize);
48 static int devsymLock(sqlite3_file*, int);
49 static int devsymUnlock(sqlite3_file*, int);
50 static int devsymCheckReservedLock(sqlite3_file*, int *);
51 static int devsymFileControl(sqlite3_file*, int op, void *pArg);
52 static int devsymSectorSize(sqlite3_file*);
53 static int devsymDeviceCharacteristics(sqlite3_file*);
54 static int devsymShmLock(sqlite3_file*,int,int,int);
55 static int devsymShmMap(sqlite3_file*,int,int,int, void volatile **);
56 static void devsymShmBarrier(sqlite3_file*);
57 static int devsymShmUnmap(sqlite3_file*,int);
58
59 /*
60 ** Method declarations for devsym_vfs.
61 */
62 static int devsymOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
63 static int devsymDelete(sqlite3_vfs*, const char *zName, int syncDir);
64 static int devsymAccess(sqlite3_vfs*, const char *zName, int flags, int *);
65 static int devsymFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
66 #ifndef SQLITE_OMIT_LOAD_EXTENSION
67 static void *devsymDlOpen(sqlite3_vfs*, const char *zFilename);
68 static void devsymDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
69 static void (*devsymDlSym(sqlite3_vfs*,void*, const char *zSymbol))(void);
70 static void devsymDlClose(sqlite3_vfs*, void*);
71 #endif /* SQLITE_OMIT_LOAD_EXTENSION */
72 static int devsymRandomness(sqlite3_vfs*, int nByte, char *zOut);
73 static int devsymSleep(sqlite3_vfs*, int microseconds);
74 static int devsymCurrentTime(sqlite3_vfs*, double*);
75
76 struct DevsymGlobal {
77 sqlite3_vfs *pVfs;
78 int iDeviceChar;
79 int iSectorSize;
80 int nWriteCrash;
81 };
82 struct DevsymGlobal g = {0, 0, 512, 0};
83
84 /*
85 ** Close an devsym-file.
86 */
devsymClose(sqlite3_file * pFile)87 static int devsymClose(sqlite3_file *pFile){
88 devsym_file *p = (devsym_file *)pFile;
89 sqlite3OsClose(p->pReal);
90 return SQLITE_OK;
91 }
92
93 /*
94 ** Read data from an devsym-file.
95 */
devsymRead(sqlite3_file * pFile,void * zBuf,int iAmt,sqlite_int64 iOfst)96 static int devsymRead(
97 sqlite3_file *pFile,
98 void *zBuf,
99 int iAmt,
100 sqlite_int64 iOfst
101 ){
102 devsym_file *p = (devsym_file *)pFile;
103 return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
104 }
105
106 /*
107 ** Write data to an devsym-file.
108 */
devsymWrite(sqlite3_file * pFile,const void * zBuf,int iAmt,sqlite_int64 iOfst)109 static int devsymWrite(
110 sqlite3_file *pFile,
111 const void *zBuf,
112 int iAmt,
113 sqlite_int64 iOfst
114 ){
115 devsym_file *p = (devsym_file *)pFile;
116 return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
117 }
118
119 /*
120 ** Truncate an devsym-file.
121 */
devsymTruncate(sqlite3_file * pFile,sqlite_int64 size)122 static int devsymTruncate(sqlite3_file *pFile, sqlite_int64 size){
123 devsym_file *p = (devsym_file *)pFile;
124 return sqlite3OsTruncate(p->pReal, size);
125 }
126
127 /*
128 ** Sync an devsym-file.
129 */
devsymSync(sqlite3_file * pFile,int flags)130 static int devsymSync(sqlite3_file *pFile, int flags){
131 devsym_file *p = (devsym_file *)pFile;
132 return sqlite3OsSync(p->pReal, flags);
133 }
134
135 /*
136 ** Return the current file-size of an devsym-file.
137 */
devsymFileSize(sqlite3_file * pFile,sqlite_int64 * pSize)138 static int devsymFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
139 devsym_file *p = (devsym_file *)pFile;
140 return sqlite3OsFileSize(p->pReal, pSize);
141 }
142
143 /*
144 ** Lock an devsym-file.
145 */
devsymLock(sqlite3_file * pFile,int eLock)146 static int devsymLock(sqlite3_file *pFile, int eLock){
147 devsym_file *p = (devsym_file *)pFile;
148 return sqlite3OsLock(p->pReal, eLock);
149 }
150
151 /*
152 ** Unlock an devsym-file.
153 */
devsymUnlock(sqlite3_file * pFile,int eLock)154 static int devsymUnlock(sqlite3_file *pFile, int eLock){
155 devsym_file *p = (devsym_file *)pFile;
156 return sqlite3OsUnlock(p->pReal, eLock);
157 }
158
159 /*
160 ** Check if another file-handle holds a RESERVED lock on an devsym-file.
161 */
devsymCheckReservedLock(sqlite3_file * pFile,int * pResOut)162 static int devsymCheckReservedLock(sqlite3_file *pFile, int *pResOut){
163 devsym_file *p = (devsym_file *)pFile;
164 return sqlite3OsCheckReservedLock(p->pReal, pResOut);
165 }
166
167 /*
168 ** File control method. For custom operations on an devsym-file.
169 */
devsymFileControl(sqlite3_file * pFile,int op,void * pArg)170 static int devsymFileControl(sqlite3_file *pFile, int op, void *pArg){
171 devsym_file *p = (devsym_file *)pFile;
172 return sqlite3OsFileControl(p->pReal, op, pArg);
173 }
174
175 /*
176 ** Return the sector-size in bytes for an devsym-file.
177 */
devsymSectorSize(sqlite3_file * pFile)178 static int devsymSectorSize(sqlite3_file *pFile){
179 return g.iSectorSize;
180 }
181
182 /*
183 ** Return the device characteristic flags supported by an devsym-file.
184 */
devsymDeviceCharacteristics(sqlite3_file * pFile)185 static int devsymDeviceCharacteristics(sqlite3_file *pFile){
186 return g.iDeviceChar;
187 }
188
189 /*
190 ** Shared-memory methods are all pass-thrus.
191 */
devsymShmLock(sqlite3_file * pFile,int ofst,int n,int flags)192 static int devsymShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
193 devsym_file *p = (devsym_file *)pFile;
194 return p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
195 }
devsymShmMap(sqlite3_file * pFile,int iRegion,int szRegion,int isWrite,void volatile ** pp)196 static int devsymShmMap(
197 sqlite3_file *pFile,
198 int iRegion,
199 int szRegion,
200 int isWrite,
201 void volatile **pp
202 ){
203 devsym_file *p = (devsym_file *)pFile;
204 return p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
205 }
devsymShmBarrier(sqlite3_file * pFile)206 static void devsymShmBarrier(sqlite3_file *pFile){
207 devsym_file *p = (devsym_file *)pFile;
208 p->pReal->pMethods->xShmBarrier(p->pReal);
209 }
devsymShmUnmap(sqlite3_file * pFile,int delFlag)210 static int devsymShmUnmap(sqlite3_file *pFile, int delFlag){
211 devsym_file *p = (devsym_file *)pFile;
212 return p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
213 }
214
215
216
217 /*
218 ** Open an devsym file handle.
219 */
devsymOpen(sqlite3_vfs * pVfs,const char * zName,sqlite3_file * pFile,int flags,int * pOutFlags)220 static int devsymOpen(
221 sqlite3_vfs *pVfs,
222 const char *zName,
223 sqlite3_file *pFile,
224 int flags,
225 int *pOutFlags
226 ){
227 static sqlite3_io_methods devsym_io_methods = {
228 2, /* iVersion */
229 devsymClose, /* xClose */
230 devsymRead, /* xRead */
231 devsymWrite, /* xWrite */
232 devsymTruncate, /* xTruncate */
233 devsymSync, /* xSync */
234 devsymFileSize, /* xFileSize */
235 devsymLock, /* xLock */
236 devsymUnlock, /* xUnlock */
237 devsymCheckReservedLock, /* xCheckReservedLock */
238 devsymFileControl, /* xFileControl */
239 devsymSectorSize, /* xSectorSize */
240 devsymDeviceCharacteristics, /* xDeviceCharacteristics */
241 devsymShmMap, /* xShmMap */
242 devsymShmLock, /* xShmLock */
243 devsymShmBarrier, /* xShmBarrier */
244 devsymShmUnmap /* xShmUnmap */
245 };
246
247 int rc;
248 devsym_file *p = (devsym_file *)pFile;
249 p->pReal = (sqlite3_file *)&p[1];
250 rc = sqlite3OsOpen(g.pVfs, zName, p->pReal, flags, pOutFlags);
251 if( p->pReal->pMethods ){
252 pFile->pMethods = &devsym_io_methods;
253 }
254 return rc;
255 }
256
257 /*
258 ** Delete the file located at zPath. If the dirSync argument is true,
259 ** ensure the file-system modifications are synced to disk before
260 ** returning.
261 */
devsymDelete(sqlite3_vfs * pVfs,const char * zPath,int dirSync)262 static int devsymDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
263 return sqlite3OsDelete(g.pVfs, zPath, dirSync);
264 }
265
266 /*
267 ** Test for access permissions. Return true if the requested permission
268 ** is available, or false otherwise.
269 */
devsymAccess(sqlite3_vfs * pVfs,const char * zPath,int flags,int * pResOut)270 static int devsymAccess(
271 sqlite3_vfs *pVfs,
272 const char *zPath,
273 int flags,
274 int *pResOut
275 ){
276 return sqlite3OsAccess(g.pVfs, zPath, flags, pResOut);
277 }
278
279 /*
280 ** Populate buffer zOut with the full canonical pathname corresponding
281 ** to the pathname in zPath. zOut is guaranteed to point to a buffer
282 ** of at least (DEVSYM_MAX_PATHNAME+1) bytes.
283 */
devsymFullPathname(sqlite3_vfs * pVfs,const char * zPath,int nOut,char * zOut)284 static int devsymFullPathname(
285 sqlite3_vfs *pVfs,
286 const char *zPath,
287 int nOut,
288 char *zOut
289 ){
290 return sqlite3OsFullPathname(g.pVfs, zPath, nOut, zOut);
291 }
292
293 #ifndef SQLITE_OMIT_LOAD_EXTENSION
294 /*
295 ** Open the dynamic library located at zPath and return a handle.
296 */
devsymDlOpen(sqlite3_vfs * pVfs,const char * zPath)297 static void *devsymDlOpen(sqlite3_vfs *pVfs, const char *zPath){
298 return sqlite3OsDlOpen(g.pVfs, zPath);
299 }
300
301 /*
302 ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
303 ** utf-8 string describing the most recent error encountered associated
304 ** with dynamic libraries.
305 */
devsymDlError(sqlite3_vfs * pVfs,int nByte,char * zErrMsg)306 static void devsymDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
307 sqlite3OsDlError(g.pVfs, nByte, zErrMsg);
308 }
309
310 /*
311 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
312 */
devsymDlSym(sqlite3_vfs * pVfs,void * p,const char * zSym)313 static void (*devsymDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
314 return sqlite3OsDlSym(g.pVfs, p, zSym);
315 }
316
317 /*
318 ** Close the dynamic library handle pHandle.
319 */
devsymDlClose(sqlite3_vfs * pVfs,void * pHandle)320 static void devsymDlClose(sqlite3_vfs *pVfs, void *pHandle){
321 sqlite3OsDlClose(g.pVfs, pHandle);
322 }
323 #endif /* SQLITE_OMIT_LOAD_EXTENSION */
324
325 /*
326 ** Populate the buffer pointed to by zBufOut with nByte bytes of
327 ** random data.
328 */
devsymRandomness(sqlite3_vfs * pVfs,int nByte,char * zBufOut)329 static int devsymRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
330 return sqlite3OsRandomness(g.pVfs, nByte, zBufOut);
331 }
332
333 /*
334 ** Sleep for nMicro microseconds. Return the number of microseconds
335 ** actually slept.
336 */
devsymSleep(sqlite3_vfs * pVfs,int nMicro)337 static int devsymSleep(sqlite3_vfs *pVfs, int nMicro){
338 return sqlite3OsSleep(g.pVfs, nMicro);
339 }
340
341 /*
342 ** Return the current time as a Julian Day number in *pTimeOut.
343 */
devsymCurrentTime(sqlite3_vfs * pVfs,double * pTimeOut)344 static int devsymCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
345 return g.pVfs->xCurrentTime(g.pVfs, pTimeOut);
346 }
347
348 /*
349 ** Return the sector-size in bytes for an writecrash-file.
350 */
writecrashSectorSize(sqlite3_file * pFile)351 static int writecrashSectorSize(sqlite3_file *pFile){
352 devsym_file *p = (devsym_file *)pFile;
353 return sqlite3OsSectorSize(p->pReal);
354 }
355
356 /*
357 ** Return the device characteristic flags supported by an writecrash-file.
358 */
writecrashDeviceCharacteristics(sqlite3_file * pFile)359 static int writecrashDeviceCharacteristics(sqlite3_file *pFile){
360 devsym_file *p = (devsym_file *)pFile;
361 return sqlite3OsDeviceCharacteristics(p->pReal);
362 }
363
364 /*
365 ** Write data to an writecrash-file.
366 */
writecrashWrite(sqlite3_file * pFile,const void * zBuf,int iAmt,sqlite_int64 iOfst)367 static int writecrashWrite(
368 sqlite3_file *pFile,
369 const void *zBuf,
370 int iAmt,
371 sqlite_int64 iOfst
372 ){
373 devsym_file *p = (devsym_file *)pFile;
374 if( g.nWriteCrash>0 ){
375 g.nWriteCrash--;
376 if( g.nWriteCrash==0 ) abort();
377 }
378 return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
379 }
380
381 /*
382 ** Open an writecrash file handle.
383 */
writecrashOpen(sqlite3_vfs * pVfs,const char * zName,sqlite3_file * pFile,int flags,int * pOutFlags)384 static int writecrashOpen(
385 sqlite3_vfs *pVfs,
386 const char *zName,
387 sqlite3_file *pFile,
388 int flags,
389 int *pOutFlags
390 ){
391 static sqlite3_io_methods writecrash_io_methods = {
392 2, /* iVersion */
393 devsymClose, /* xClose */
394 devsymRead, /* xRead */
395 writecrashWrite, /* xWrite */
396 devsymTruncate, /* xTruncate */
397 devsymSync, /* xSync */
398 devsymFileSize, /* xFileSize */
399 devsymLock, /* xLock */
400 devsymUnlock, /* xUnlock */
401 devsymCheckReservedLock, /* xCheckReservedLock */
402 devsymFileControl, /* xFileControl */
403 writecrashSectorSize, /* xSectorSize */
404 writecrashDeviceCharacteristics, /* xDeviceCharacteristics */
405 devsymShmMap, /* xShmMap */
406 devsymShmLock, /* xShmLock */
407 devsymShmBarrier, /* xShmBarrier */
408 devsymShmUnmap /* xShmUnmap */
409 };
410
411 int rc;
412 devsym_file *p = (devsym_file *)pFile;
413 p->pReal = (sqlite3_file *)&p[1];
414 rc = sqlite3OsOpen(g.pVfs, zName, p->pReal, flags, pOutFlags);
415 if( p->pReal->pMethods ){
416 pFile->pMethods = &writecrash_io_methods;
417 }
418 return rc;
419 }
420
421 static sqlite3_vfs devsym_vfs = {
422 2, /* iVersion */
423 sizeof(devsym_file), /* szOsFile */
424 DEVSYM_MAX_PATHNAME, /* mxPathname */
425 0, /* pNext */
426 DEVSYM_VFS_NAME, /* zName */
427 0, /* pAppData */
428 devsymOpen, /* xOpen */
429 devsymDelete, /* xDelete */
430 devsymAccess, /* xAccess */
431 devsymFullPathname, /* xFullPathname */
432 #ifndef SQLITE_OMIT_LOAD_EXTENSION
433 devsymDlOpen, /* xDlOpen */
434 devsymDlError, /* xDlError */
435 devsymDlSym, /* xDlSym */
436 devsymDlClose, /* xDlClose */
437 #else
438 0, /* xDlOpen */
439 0, /* xDlError */
440 0, /* xDlSym */
441 0, /* xDlClose */
442 #endif /* SQLITE_OMIT_LOAD_EXTENSION */
443 devsymRandomness, /* xRandomness */
444 devsymSleep, /* xSleep */
445 devsymCurrentTime, /* xCurrentTime */
446 0, /* xGetLastError */
447 0 /* xCurrentTimeInt64 */
448 };
449
450 static sqlite3_vfs writecrash_vfs = {
451 2, /* iVersion */
452 sizeof(devsym_file), /* szOsFile */
453 DEVSYM_MAX_PATHNAME, /* mxPathname */
454 0, /* pNext */
455 WRITECRASH_NAME, /* zName */
456 0, /* pAppData */
457 writecrashOpen, /* xOpen */
458 devsymDelete, /* xDelete */
459 devsymAccess, /* xAccess */
460 devsymFullPathname, /* xFullPathname */
461 #ifndef SQLITE_OMIT_LOAD_EXTENSION
462 devsymDlOpen, /* xDlOpen */
463 devsymDlError, /* xDlError */
464 devsymDlSym, /* xDlSym */
465 devsymDlClose, /* xDlClose */
466 #else
467 0, /* xDlOpen */
468 0, /* xDlError */
469 0, /* xDlSym */
470 0, /* xDlClose */
471 #endif /* SQLITE_OMIT_LOAD_EXTENSION */
472 devsymRandomness, /* xRandomness */
473 devsymSleep, /* xSleep */
474 devsymCurrentTime, /* xCurrentTime */
475 0, /* xGetLastError */
476 0 /* xCurrentTimeInt64 */
477 };
478
479
480 /*
481 ** This procedure registers the devsym vfs with SQLite. If the argument is
482 ** true, the devsym vfs becomes the new default vfs. It is the only publicly
483 ** available function in this file.
484 */
devsym_register(int iDeviceChar,int iSectorSize)485 void devsym_register(int iDeviceChar, int iSectorSize){
486
487 if( g.pVfs==0 ){
488 g.pVfs = sqlite3_vfs_find(0);
489 devsym_vfs.szOsFile += g.pVfs->szOsFile;
490 writecrash_vfs.szOsFile += g.pVfs->szOsFile;
491 sqlite3_vfs_register(&devsym_vfs, 0);
492 sqlite3_vfs_register(&writecrash_vfs, 0);
493 }
494 if( iDeviceChar>=0 ){
495 g.iDeviceChar = iDeviceChar;
496 }else{
497 g.iDeviceChar = 0;
498 }
499 if( iSectorSize>=0 ){
500 g.iSectorSize = iSectorSize;
501 }else{
502 g.iSectorSize = 512;
503 }
504 }
505
devsym_unregister()506 void devsym_unregister(){
507 sqlite3_vfs_unregister(&devsym_vfs);
508 sqlite3_vfs_unregister(&writecrash_vfs);
509 g.pVfs = 0;
510 g.iDeviceChar = 0;
511 g.iSectorSize = 0;
512 }
513
devsym_crash_on_write(int nWrite)514 void devsym_crash_on_write(int nWrite){
515 if( g.pVfs==0 ){
516 g.pVfs = sqlite3_vfs_find(0);
517 devsym_vfs.szOsFile += g.pVfs->szOsFile;
518 writecrash_vfs.szOsFile += g.pVfs->szOsFile;
519 sqlite3_vfs_register(&devsym_vfs, 0);
520 sqlite3_vfs_register(&writecrash_vfs, 0);
521 }
522 g.nWriteCrash = nWrite;
523 }
524
525 #endif
526