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
32typedef struct devsym_file devsym_file;
33struct devsym_file {
34  sqlite3_file base;
35  sqlite3_file *pReal;
36};
37
38/*
39** Method declarations for devsym_file.
40*/
41static int devsymClose(sqlite3_file*);
42static int devsymRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
43static int devsymWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
44static int devsymTruncate(sqlite3_file*, sqlite3_int64 size);
45static int devsymSync(sqlite3_file*, int flags);
46static int devsymFileSize(sqlite3_file*, sqlite3_int64 *pSize);
47static int devsymLock(sqlite3_file*, int);
48static int devsymUnlock(sqlite3_file*, int);
49static int devsymCheckReservedLock(sqlite3_file*, int *);
50static int devsymFileControl(sqlite3_file*, int op, void *pArg);
51static int devsymSectorSize(sqlite3_file*);
52static int devsymDeviceCharacteristics(sqlite3_file*);
53static int devsymShmLock(sqlite3_file*,int,int,int);
54static int devsymShmMap(sqlite3_file*,int,int,int, void volatile **);
55static void devsymShmBarrier(sqlite3_file*);
56static int devsymShmUnmap(sqlite3_file*,int);
57
58/*
59** Method declarations for devsym_vfs.
60*/
61static int devsymOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
62static int devsymDelete(sqlite3_vfs*, const char *zName, int syncDir);
63static int devsymAccess(sqlite3_vfs*, const char *zName, int flags, int *);
64static int devsymFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
65#ifndef SQLITE_OMIT_LOAD_EXTENSION
66static void *devsymDlOpen(sqlite3_vfs*, const char *zFilename);
67static void devsymDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
68static void (*devsymDlSym(sqlite3_vfs*,void*, const char *zSymbol))(void);
69static void devsymDlClose(sqlite3_vfs*, void*);
70#endif /* SQLITE_OMIT_LOAD_EXTENSION */
71static int devsymRandomness(sqlite3_vfs*, int nByte, char *zOut);
72static int devsymSleep(sqlite3_vfs*, int microseconds);
73static int devsymCurrentTime(sqlite3_vfs*, double*);
74
75static sqlite3_vfs devsym_vfs = {
76  2,                     /* iVersion */
77  sizeof(devsym_file),      /* szOsFile */
78  DEVSYM_MAX_PATHNAME,      /* mxPathname */
79  0,                     /* pNext */
80  DEVSYM_VFS_NAME,          /* zName */
81  0,                     /* pAppData */
82  devsymOpen,               /* xOpen */
83  devsymDelete,             /* xDelete */
84  devsymAccess,             /* xAccess */
85  devsymFullPathname,       /* xFullPathname */
86#ifndef SQLITE_OMIT_LOAD_EXTENSION
87  devsymDlOpen,             /* xDlOpen */
88  devsymDlError,            /* xDlError */
89  devsymDlSym,              /* xDlSym */
90  devsymDlClose,            /* xDlClose */
91#else
92  0,                        /* xDlOpen */
93  0,                        /* xDlError */
94  0,                        /* xDlSym */
95  0,                        /* xDlClose */
96#endif /* SQLITE_OMIT_LOAD_EXTENSION */
97  devsymRandomness,         /* xRandomness */
98  devsymSleep,              /* xSleep */
99  devsymCurrentTime,        /* xCurrentTime */
100  0,                        /* xGetLastError */
101  0                         /* xCurrentTimeInt64 */
102};
103
104static sqlite3_io_methods devsym_io_methods = {
105  2,                                /* iVersion */
106  devsymClose,                      /* xClose */
107  devsymRead,                       /* xRead */
108  devsymWrite,                      /* xWrite */
109  devsymTruncate,                   /* xTruncate */
110  devsymSync,                       /* xSync */
111  devsymFileSize,                   /* xFileSize */
112  devsymLock,                       /* xLock */
113  devsymUnlock,                     /* xUnlock */
114  devsymCheckReservedLock,          /* xCheckReservedLock */
115  devsymFileControl,                /* xFileControl */
116  devsymSectorSize,                 /* xSectorSize */
117  devsymDeviceCharacteristics,      /* xDeviceCharacteristics */
118  devsymShmMap,                     /* xShmMap */
119  devsymShmLock,                    /* xShmLock */
120  devsymShmBarrier,                 /* xShmBarrier */
121  devsymShmUnmap                    /* xShmUnmap */
122};
123
124struct DevsymGlobal {
125  sqlite3_vfs *pVfs;
126  int iDeviceChar;
127  int iSectorSize;
128};
129struct DevsymGlobal g = {0, 0, 512};
130
131/*
132** Close an devsym-file.
133*/
134static int devsymClose(sqlite3_file *pFile){
135  devsym_file *p = (devsym_file *)pFile;
136  return sqlite3OsClose(p->pReal);
137}
138
139/*
140** Read data from an devsym-file.
141*/
142static int devsymRead(
143  sqlite3_file *pFile,
144  void *zBuf,
145  int iAmt,
146  sqlite_int64 iOfst
147){
148  devsym_file *p = (devsym_file *)pFile;
149  return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
150}
151
152/*
153** Write data to an devsym-file.
154*/
155static int devsymWrite(
156  sqlite3_file *pFile,
157  const void *zBuf,
158  int iAmt,
159  sqlite_int64 iOfst
160){
161  devsym_file *p = (devsym_file *)pFile;
162  return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
163}
164
165/*
166** Truncate an devsym-file.
167*/
168static int devsymTruncate(sqlite3_file *pFile, sqlite_int64 size){
169  devsym_file *p = (devsym_file *)pFile;
170  return sqlite3OsTruncate(p->pReal, size);
171}
172
173/*
174** Sync an devsym-file.
175*/
176static int devsymSync(sqlite3_file *pFile, int flags){
177  devsym_file *p = (devsym_file *)pFile;
178  return sqlite3OsSync(p->pReal, flags);
179}
180
181/*
182** Return the current file-size of an devsym-file.
183*/
184static int devsymFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
185  devsym_file *p = (devsym_file *)pFile;
186  return sqlite3OsFileSize(p->pReal, pSize);
187}
188
189/*
190** Lock an devsym-file.
191*/
192static int devsymLock(sqlite3_file *pFile, int eLock){
193  devsym_file *p = (devsym_file *)pFile;
194  return sqlite3OsLock(p->pReal, eLock);
195}
196
197/*
198** Unlock an devsym-file.
199*/
200static int devsymUnlock(sqlite3_file *pFile, int eLock){
201  devsym_file *p = (devsym_file *)pFile;
202  return sqlite3OsUnlock(p->pReal, eLock);
203}
204
205/*
206** Check if another file-handle holds a RESERVED lock on an devsym-file.
207*/
208static int devsymCheckReservedLock(sqlite3_file *pFile, int *pResOut){
209  devsym_file *p = (devsym_file *)pFile;
210  return sqlite3OsCheckReservedLock(p->pReal, pResOut);
211}
212
213/*
214** File control method. For custom operations on an devsym-file.
215*/
216static int devsymFileControl(sqlite3_file *pFile, int op, void *pArg){
217  devsym_file *p = (devsym_file *)pFile;
218  return sqlite3OsFileControl(p->pReal, op, pArg);
219}
220
221/*
222** Return the sector-size in bytes for an devsym-file.
223*/
224static int devsymSectorSize(sqlite3_file *pFile){
225  return g.iSectorSize;
226}
227
228/*
229** Return the device characteristic flags supported by an devsym-file.
230*/
231static int devsymDeviceCharacteristics(sqlite3_file *pFile){
232  return g.iDeviceChar;
233}
234
235/*
236** Shared-memory methods are all pass-thrus.
237*/
238static int devsymShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
239  devsym_file *p = (devsym_file *)pFile;
240  return sqlite3OsShmLock(p->pReal, ofst, n, flags);
241}
242static int devsymShmMap(
243  sqlite3_file *pFile,
244  int iRegion,
245  int szRegion,
246  int isWrite,
247  void volatile **pp
248){
249  devsym_file *p = (devsym_file *)pFile;
250  return sqlite3OsShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
251}
252static void devsymShmBarrier(sqlite3_file *pFile){
253  devsym_file *p = (devsym_file *)pFile;
254  sqlite3OsShmBarrier(p->pReal);
255}
256static int devsymShmUnmap(sqlite3_file *pFile, int delFlag){
257  devsym_file *p = (devsym_file *)pFile;
258  return sqlite3OsShmUnmap(p->pReal, delFlag);
259}
260
261
262
263/*
264** Open an devsym file handle.
265*/
266static int devsymOpen(
267  sqlite3_vfs *pVfs,
268  const char *zName,
269  sqlite3_file *pFile,
270  int flags,
271  int *pOutFlags
272){
273  int rc;
274  devsym_file *p = (devsym_file *)pFile;
275  p->pReal = (sqlite3_file *)&p[1];
276  rc = sqlite3OsOpen(g.pVfs, zName, p->pReal, flags, pOutFlags);
277  if( p->pReal->pMethods ){
278    pFile->pMethods = &devsym_io_methods;
279  }
280  return rc;
281}
282
283/*
284** Delete the file located at zPath. If the dirSync argument is true,
285** ensure the file-system modifications are synced to disk before
286** returning.
287*/
288static int devsymDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
289  return sqlite3OsDelete(g.pVfs, zPath, dirSync);
290}
291
292/*
293** Test for access permissions. Return true if the requested permission
294** is available, or false otherwise.
295*/
296static int devsymAccess(
297  sqlite3_vfs *pVfs,
298  const char *zPath,
299  int flags,
300  int *pResOut
301){
302  return sqlite3OsAccess(g.pVfs, zPath, flags, pResOut);
303}
304
305/*
306** Populate buffer zOut with the full canonical pathname corresponding
307** to the pathname in zPath. zOut is guaranteed to point to a buffer
308** of at least (DEVSYM_MAX_PATHNAME+1) bytes.
309*/
310static int devsymFullPathname(
311  sqlite3_vfs *pVfs,
312  const char *zPath,
313  int nOut,
314  char *zOut
315){
316  return sqlite3OsFullPathname(g.pVfs, zPath, nOut, zOut);
317}
318
319#ifndef SQLITE_OMIT_LOAD_EXTENSION
320/*
321** Open the dynamic library located at zPath and return a handle.
322*/
323static void *devsymDlOpen(sqlite3_vfs *pVfs, const char *zPath){
324  return sqlite3OsDlOpen(g.pVfs, zPath);
325}
326
327/*
328** Populate the buffer zErrMsg (size nByte bytes) with a human readable
329** utf-8 string describing the most recent error encountered associated
330** with dynamic libraries.
331*/
332static void devsymDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
333  sqlite3OsDlError(g.pVfs, nByte, zErrMsg);
334}
335
336/*
337** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
338*/
339static void (*devsymDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
340  return sqlite3OsDlSym(g.pVfs, p, zSym);
341}
342
343/*
344** Close the dynamic library handle pHandle.
345*/
346static void devsymDlClose(sqlite3_vfs *pVfs, void *pHandle){
347  sqlite3OsDlClose(g.pVfs, pHandle);
348}
349#endif /* SQLITE_OMIT_LOAD_EXTENSION */
350
351/*
352** Populate the buffer pointed to by zBufOut with nByte bytes of
353** random data.
354*/
355static int devsymRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
356  return sqlite3OsRandomness(g.pVfs, nByte, zBufOut);
357}
358
359/*
360** Sleep for nMicro microseconds. Return the number of microseconds
361** actually slept.
362*/
363static int devsymSleep(sqlite3_vfs *pVfs, int nMicro){
364  return sqlite3OsSleep(g.pVfs, nMicro);
365}
366
367/*
368** Return the current time as a Julian Day number in *pTimeOut.
369*/
370static int devsymCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
371  return g.pVfs->xCurrentTime(g.pVfs, pTimeOut);
372}
373
374
375/*
376** This procedure registers the devsym vfs with SQLite. If the argument is
377** true, the devsym vfs becomes the new default vfs. It is the only publicly
378** available function in this file.
379*/
380void devsym_register(int iDeviceChar, int iSectorSize){
381  if( g.pVfs==0 ){
382    g.pVfs = sqlite3_vfs_find(0);
383    devsym_vfs.szOsFile += g.pVfs->szOsFile;
384    sqlite3_vfs_register(&devsym_vfs, 0);
385  }
386  if( iDeviceChar>=0 ){
387    g.iDeviceChar = iDeviceChar;
388  }else{
389    g.iDeviceChar = 0;
390  }
391  if( iSectorSize>=0 ){
392    g.iSectorSize = iSectorSize;
393  }else{
394    g.iSectorSize = 512;
395  }
396}
397
398#endif
399