197ae8ffbSdrh /*
297ae8ffbSdrh ** 2011 March 16
397ae8ffbSdrh **
497ae8ffbSdrh ** The author disclaims copyright to this source code. In place of
597ae8ffbSdrh ** a legal notice, here is a blessing:
697ae8ffbSdrh **
797ae8ffbSdrh ** May you do good and not evil.
897ae8ffbSdrh ** May you find forgiveness for yourself and forgive others.
997ae8ffbSdrh ** May you share freely, never taking more than you give.
1097ae8ffbSdrh **
1197ae8ffbSdrh ******************************************************************************
1297ae8ffbSdrh **
1397ae8ffbSdrh ** This file contains code implements a VFS shim that writes diagnostic
1497ae8ffbSdrh ** output for each VFS call, similar to "strace".
15cf8112beSdrh **
16cf8112beSdrh ** USAGE:
17cf8112beSdrh **
18cf8112beSdrh ** This source file exports a single symbol which is the name of a
19cf8112beSdrh ** function:
20cf8112beSdrh **
21cf8112beSdrh ** int vfstrace_register(
22cf8112beSdrh ** const char *zTraceName, // Name of the newly constructed VFS
23cf8112beSdrh ** const char *zOldVfsName, // Name of the underlying VFS
24cf8112beSdrh ** int (*xOut)(const char*,void*), // Output routine. ex: fputs
25cf8112beSdrh ** void *pOutArg, // 2nd argument to xOut. ex: stderr
26cf8112beSdrh ** int makeDefault // Make the new VFS the default
27cf8112beSdrh ** );
28cf8112beSdrh **
29cf8112beSdrh ** Applications that want to trace their VFS usage must provide a callback
30cf8112beSdrh ** function with this prototype:
31cf8112beSdrh **
32cf8112beSdrh ** int traceOutput(const char *zMessage, void *pAppData);
33cf8112beSdrh **
34cf8112beSdrh ** This function will "output" the trace messages, where "output" can
35cf8112beSdrh ** mean different things to different applications. The traceOutput function
36cf8112beSdrh ** for the command-line shell (see shell.c) is "fputs" from the standard
37cf8112beSdrh ** library, which means that all trace output is written on the stream
38cf8112beSdrh ** specified by the second argument. In the case of the command-line shell
39cf8112beSdrh ** the second argument is stderr. Other applications might choose to output
40cf8112beSdrh ** trace information to a file, over a socket, or write it into a buffer.
41cf8112beSdrh **
42cf8112beSdrh ** The vfstrace_register() function creates a new "shim" VFS named by
43cf8112beSdrh ** the zTraceName parameter. A "shim" VFS is an SQLite backend that does
44cf8112beSdrh ** not really perform the duties of a true backend, but simply filters or
45cf8112beSdrh ** interprets VFS calls before passing them off to another VFS which does
46cf8112beSdrh ** the actual work. In this case the other VFS - the one that does the
47cf8112beSdrh ** real work - is identified by the second parameter, zOldVfsName. If
48d5578433Smistachkin ** the 2nd parameter is NULL then the default VFS is used. The common
49cf8112beSdrh ** case is for the 2nd parameter to be NULL.
50cf8112beSdrh **
51cf8112beSdrh ** The third and fourth parameters are the pointer to the output function
52cf8112beSdrh ** and the second argument to the output function. For the SQLite
53cf8112beSdrh ** command-line shell, when the -vfstrace option is used, these parameters
54cf8112beSdrh ** are fputs and stderr, respectively.
55cf8112beSdrh **
56cf8112beSdrh ** The fifth argument is true (non-zero) to cause the newly created VFS
57cf8112beSdrh ** to become the default VFS. The common case is for the fifth parameter
58cf8112beSdrh ** to be true.
59cf8112beSdrh **
60cf8112beSdrh ** The call to vfstrace_register() simply creates the shim VFS that does
61cf8112beSdrh ** tracing. The application must also arrange to use the new VFS for
62cf8112beSdrh ** all database connections that are created and for which tracing is
63cf8112beSdrh ** desired. This can be done by specifying the trace VFS using URI filename
64cf8112beSdrh ** notation, or by specifying the trace VFS as the 4th parameter to
65cf8112beSdrh ** sqlite3_open_v2() or by making the trace VFS be the default (by setting
66cf8112beSdrh ** the 5th parameter of vfstrace_register() to 1).
67cf8112beSdrh **
68cf8112beSdrh **
69cf8112beSdrh ** ENABLING VFSTRACE IN A COMMAND-LINE SHELL
70cf8112beSdrh **
71cf8112beSdrh ** The SQLite command line shell implemented by the shell.c source file
72cf8112beSdrh ** can be used with this module. To compile in -vfstrace support, first
73cf8112beSdrh ** gather this file (test_vfstrace.c), the shell source file (shell.c),
74cf8112beSdrh ** and the SQLite amalgamation source files (sqlite3.c, sqlite3.h) into
75cf8112beSdrh ** the working directory. Then compile using a command like the following:
76cf8112beSdrh **
77cf8112beSdrh ** gcc -o sqlite3 -Os -I. -DSQLITE_ENABLE_VFSTRACE \
78cf8112beSdrh ** -DSQLITE_THREADSAFE=0 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \
79cf8112beSdrh ** -DHAVE_READLINE -DHAVE_USLEEP=1 \
80cf8112beSdrh ** shell.c test_vfstrace.c sqlite3.c -ldl -lreadline -lncurses
81cf8112beSdrh **
82cf8112beSdrh ** The gcc command above works on Linux and provides (in addition to the
83cf8112beSdrh ** -vfstrace option) support for FTS3 and FTS4, RTREE, and command-line
84cf8112beSdrh ** editing using the readline library. The command-line shell does not
85cf8112beSdrh ** use threads so we added -DSQLITE_THREADSAFE=0 just to make the code
86cf8112beSdrh ** run a little faster. For compiling on a Mac, you'll probably need
87cf8112beSdrh ** to omit the -DHAVE_READLINE, the -lreadline, and the -lncurses options.
88cf8112beSdrh ** The compilation could be simplified to just this:
89cf8112beSdrh **
90cf8112beSdrh ** gcc -DSQLITE_ENABLE_VFSTRACE \
91cf8112beSdrh ** shell.c test_vfstrace.c sqlite3.c -ldl -lpthread
92cf8112beSdrh **
93cf8112beSdrh ** In this second example, all unnecessary options have been removed
94cf8112beSdrh ** Note that since the code is now threadsafe, we had to add the -lpthread
95cf8112beSdrh ** option to pull in the pthreads library.
96cf8112beSdrh **
97cf8112beSdrh ** To cross-compile for windows using MinGW, a command like this might
98cf8112beSdrh ** work:
99cf8112beSdrh **
100cf8112beSdrh ** /opt/mingw/bin/i386-mingw32msvc-gcc -o sqlite3.exe -Os -I \
101cf8112beSdrh ** -DSQLITE_THREADSAFE=0 -DSQLITE_ENABLE_VFSTRACE \
102cf8112beSdrh ** shell.c test_vfstrace.c sqlite3.c
103cf8112beSdrh **
104cf8112beSdrh ** Similar compiler commands will work on different systems. The key
105cf8112beSdrh ** invariants are (1) you must have -DSQLITE_ENABLE_VFSTRACE so that
106cf8112beSdrh ** the shell.c source file will know to include the -vfstrace command-line
107cf8112beSdrh ** option and (2) you must compile and link the three source files
108cf8112beSdrh ** shell,c, test_vfstrace.c, and sqlite3.c.
10997ae8ffbSdrh */
11097ae8ffbSdrh #include <stdlib.h>
11197ae8ffbSdrh #include <string.h>
11297ae8ffbSdrh #include "sqlite3.h"
11397ae8ffbSdrh
11497ae8ffbSdrh /*
11597ae8ffbSdrh ** An instance of this structure is attached to the each trace VFS to
11697ae8ffbSdrh ** provide auxiliary information.
11797ae8ffbSdrh */
11897ae8ffbSdrh typedef struct vfstrace_info vfstrace_info;
11997ae8ffbSdrh struct vfstrace_info {
12097ae8ffbSdrh sqlite3_vfs *pRootVfs; /* The underlying real VFS */
12197ae8ffbSdrh int (*xOut)(const char*, void*); /* Send output here */
12297ae8ffbSdrh void *pOutArg; /* First argument to xOut */
12397ae8ffbSdrh const char *zVfsName; /* Name of this trace-VFS */
12497ae8ffbSdrh sqlite3_vfs *pTraceVfs; /* Pointer back to the trace VFS */
12597ae8ffbSdrh };
12697ae8ffbSdrh
12797ae8ffbSdrh /*
12897ae8ffbSdrh ** The sqlite3_file object for the trace VFS
12997ae8ffbSdrh */
13097ae8ffbSdrh typedef struct vfstrace_file vfstrace_file;
13197ae8ffbSdrh struct vfstrace_file {
13297ae8ffbSdrh sqlite3_file base; /* Base class. Must be first */
13397ae8ffbSdrh vfstrace_info *pInfo; /* The trace-VFS to which this file belongs */
13497ae8ffbSdrh const char *zFName; /* Base name of the file */
13597ae8ffbSdrh sqlite3_file *pReal; /* The real underlying file */
13697ae8ffbSdrh };
13797ae8ffbSdrh
13897ae8ffbSdrh /*
13997ae8ffbSdrh ** Method declarations for vfstrace_file.
14097ae8ffbSdrh */
14197ae8ffbSdrh static int vfstraceClose(sqlite3_file*);
14297ae8ffbSdrh static int vfstraceRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
14397ae8ffbSdrh static int vfstraceWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
14497ae8ffbSdrh static int vfstraceTruncate(sqlite3_file*, sqlite3_int64 size);
14597ae8ffbSdrh static int vfstraceSync(sqlite3_file*, int flags);
14697ae8ffbSdrh static int vfstraceFileSize(sqlite3_file*, sqlite3_int64 *pSize);
14797ae8ffbSdrh static int vfstraceLock(sqlite3_file*, int);
14897ae8ffbSdrh static int vfstraceUnlock(sqlite3_file*, int);
14997ae8ffbSdrh static int vfstraceCheckReservedLock(sqlite3_file*, int *);
15097ae8ffbSdrh static int vfstraceFileControl(sqlite3_file*, int op, void *pArg);
15197ae8ffbSdrh static int vfstraceSectorSize(sqlite3_file*);
15297ae8ffbSdrh static int vfstraceDeviceCharacteristics(sqlite3_file*);
15397ae8ffbSdrh static int vfstraceShmLock(sqlite3_file*,int,int,int);
15497ae8ffbSdrh static int vfstraceShmMap(sqlite3_file*,int,int,int, void volatile **);
15597ae8ffbSdrh static void vfstraceShmBarrier(sqlite3_file*);
15697ae8ffbSdrh static int vfstraceShmUnmap(sqlite3_file*,int);
15797ae8ffbSdrh
15897ae8ffbSdrh /*
15997ae8ffbSdrh ** Method declarations for vfstrace_vfs.
16097ae8ffbSdrh */
16197ae8ffbSdrh static int vfstraceOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
16297ae8ffbSdrh static int vfstraceDelete(sqlite3_vfs*, const char *zName, int syncDir);
16397ae8ffbSdrh static int vfstraceAccess(sqlite3_vfs*, const char *zName, int flags, int *);
16497ae8ffbSdrh static int vfstraceFullPathname(sqlite3_vfs*, const char *zName, int, char *);
16597ae8ffbSdrh static void *vfstraceDlOpen(sqlite3_vfs*, const char *zFilename);
16697ae8ffbSdrh static void vfstraceDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
16797ae8ffbSdrh static void (*vfstraceDlSym(sqlite3_vfs*,void*, const char *zSymbol))(void);
16897ae8ffbSdrh static void vfstraceDlClose(sqlite3_vfs*, void*);
16997ae8ffbSdrh static int vfstraceRandomness(sqlite3_vfs*, int nByte, char *zOut);
17097ae8ffbSdrh static int vfstraceSleep(sqlite3_vfs*, int microseconds);
17197ae8ffbSdrh static int vfstraceCurrentTime(sqlite3_vfs*, double*);
17297ae8ffbSdrh static int vfstraceGetLastError(sqlite3_vfs*, int, char*);
17397ae8ffbSdrh static int vfstraceCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
174943bf018Sdrh static int vfstraceSetSystemCall(sqlite3_vfs*,const char*, sqlite3_syscall_ptr);
175943bf018Sdrh static sqlite3_syscall_ptr vfstraceGetSystemCall(sqlite3_vfs*, const char *);
17697ae8ffbSdrh static const char *vfstraceNextSystemCall(sqlite3_vfs*, const char *zName);
17797ae8ffbSdrh
17897ae8ffbSdrh /*
17997ae8ffbSdrh ** Return a pointer to the tail of the pathname. Examples:
18097ae8ffbSdrh **
18197ae8ffbSdrh ** /home/drh/xyzzy.txt -> xyzzy.txt
18297ae8ffbSdrh ** xyzzy.txt -> xyzzy.txt
18397ae8ffbSdrh */
fileTail(const char * z)18497ae8ffbSdrh static const char *fileTail(const char *z){
18597ae8ffbSdrh int i;
18697ae8ffbSdrh if( z==0 ) return 0;
18797ae8ffbSdrh i = strlen(z)-1;
18897ae8ffbSdrh while( i>0 && z[i-1]!='/' ){ i--; }
18997ae8ffbSdrh return &z[i];
19097ae8ffbSdrh }
19197ae8ffbSdrh
19297ae8ffbSdrh /*
19397ae8ffbSdrh ** Send trace output defined by zFormat and subsequent arguments.
19497ae8ffbSdrh */
vfstrace_printf(vfstrace_info * pInfo,const char * zFormat,...)19597ae8ffbSdrh static void vfstrace_printf(
19697ae8ffbSdrh vfstrace_info *pInfo,
19797ae8ffbSdrh const char *zFormat,
19897ae8ffbSdrh ...
19997ae8ffbSdrh ){
20097ae8ffbSdrh va_list ap;
20197ae8ffbSdrh char *zMsg;
20297ae8ffbSdrh va_start(ap, zFormat);
20397ae8ffbSdrh zMsg = sqlite3_vmprintf(zFormat, ap);
20497ae8ffbSdrh va_end(ap);
20597ae8ffbSdrh pInfo->xOut(zMsg, pInfo->pOutArg);
20697ae8ffbSdrh sqlite3_free(zMsg);
20797ae8ffbSdrh }
20897ae8ffbSdrh
20997ae8ffbSdrh /*
21097ae8ffbSdrh ** Convert value rc into a string and print it using zFormat. zFormat
21197ae8ffbSdrh ** should have exactly one %s
21297ae8ffbSdrh */
vfstrace_print_errcode(vfstrace_info * pInfo,const char * zFormat,int rc)21397ae8ffbSdrh static void vfstrace_print_errcode(
21497ae8ffbSdrh vfstrace_info *pInfo,
21597ae8ffbSdrh const char *zFormat,
21697ae8ffbSdrh int rc
21797ae8ffbSdrh ){
21897ae8ffbSdrh char zBuf[50];
21997ae8ffbSdrh char *zVal;
22097ae8ffbSdrh switch( rc ){
22197ae8ffbSdrh case SQLITE_OK: zVal = "SQLITE_OK"; break;
22297ae8ffbSdrh case SQLITE_ERROR: zVal = "SQLITE_ERROR"; break;
22397ae8ffbSdrh case SQLITE_PERM: zVal = "SQLITE_PERM"; break;
22497ae8ffbSdrh case SQLITE_ABORT: zVal = "SQLITE_ABORT"; break;
22597ae8ffbSdrh case SQLITE_BUSY: zVal = "SQLITE_BUSY"; break;
22697ae8ffbSdrh case SQLITE_NOMEM: zVal = "SQLITE_NOMEM"; break;
22797ae8ffbSdrh case SQLITE_READONLY: zVal = "SQLITE_READONLY"; break;
22897ae8ffbSdrh case SQLITE_INTERRUPT: zVal = "SQLITE_INTERRUPT"; break;
22997ae8ffbSdrh case SQLITE_IOERR: zVal = "SQLITE_IOERR"; break;
23097ae8ffbSdrh case SQLITE_CORRUPT: zVal = "SQLITE_CORRUPT"; break;
23197ae8ffbSdrh case SQLITE_FULL: zVal = "SQLITE_FULL"; break;
23297ae8ffbSdrh case SQLITE_CANTOPEN: zVal = "SQLITE_CANTOPEN"; break;
23397ae8ffbSdrh case SQLITE_PROTOCOL: zVal = "SQLITE_PROTOCOL"; break;
23497ae8ffbSdrh case SQLITE_EMPTY: zVal = "SQLITE_EMPTY"; break;
23597ae8ffbSdrh case SQLITE_SCHEMA: zVal = "SQLITE_SCHEMA"; break;
23697ae8ffbSdrh case SQLITE_CONSTRAINT: zVal = "SQLITE_CONSTRAINT"; break;
23797ae8ffbSdrh case SQLITE_MISMATCH: zVal = "SQLITE_MISMATCH"; break;
23897ae8ffbSdrh case SQLITE_MISUSE: zVal = "SQLITE_MISUSE"; break;
23997ae8ffbSdrh case SQLITE_NOLFS: zVal = "SQLITE_NOLFS"; break;
24097ae8ffbSdrh case SQLITE_IOERR_READ: zVal = "SQLITE_IOERR_READ"; break;
24197ae8ffbSdrh case SQLITE_IOERR_SHORT_READ: zVal = "SQLITE_IOERR_SHORT_READ"; break;
24297ae8ffbSdrh case SQLITE_IOERR_WRITE: zVal = "SQLITE_IOERR_WRITE"; break;
24397ae8ffbSdrh case SQLITE_IOERR_FSYNC: zVal = "SQLITE_IOERR_FSYNC"; break;
24497ae8ffbSdrh case SQLITE_IOERR_DIR_FSYNC: zVal = "SQLITE_IOERR_DIR_FSYNC"; break;
24597ae8ffbSdrh case SQLITE_IOERR_TRUNCATE: zVal = "SQLITE_IOERR_TRUNCATE"; break;
24697ae8ffbSdrh case SQLITE_IOERR_FSTAT: zVal = "SQLITE_IOERR_FSTAT"; break;
24797ae8ffbSdrh case SQLITE_IOERR_UNLOCK: zVal = "SQLITE_IOERR_UNLOCK"; break;
24897ae8ffbSdrh case SQLITE_IOERR_RDLOCK: zVal = "SQLITE_IOERR_RDLOCK"; break;
24997ae8ffbSdrh case SQLITE_IOERR_DELETE: zVal = "SQLITE_IOERR_DELETE"; break;
25097ae8ffbSdrh case SQLITE_IOERR_BLOCKED: zVal = "SQLITE_IOERR_BLOCKED"; break;
25197ae8ffbSdrh case SQLITE_IOERR_NOMEM: zVal = "SQLITE_IOERR_NOMEM"; break;
25297ae8ffbSdrh case SQLITE_IOERR_ACCESS: zVal = "SQLITE_IOERR_ACCESS"; break;
25397ae8ffbSdrh case SQLITE_IOERR_CHECKRESERVEDLOCK:
25497ae8ffbSdrh zVal = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break;
25597ae8ffbSdrh case SQLITE_IOERR_LOCK: zVal = "SQLITE_IOERR_LOCK"; break;
25697ae8ffbSdrh case SQLITE_IOERR_CLOSE: zVal = "SQLITE_IOERR_CLOSE"; break;
25797ae8ffbSdrh case SQLITE_IOERR_DIR_CLOSE: zVal = "SQLITE_IOERR_DIR_CLOSE"; break;
25897ae8ffbSdrh case SQLITE_IOERR_SHMOPEN: zVal = "SQLITE_IOERR_SHMOPEN"; break;
25997ae8ffbSdrh case SQLITE_IOERR_SHMSIZE: zVal = "SQLITE_IOERR_SHMSIZE"; break;
26097ae8ffbSdrh case SQLITE_IOERR_SHMLOCK: zVal = "SQLITE_IOERR_SHMLOCK"; break;
2611b1f30bbSdrh case SQLITE_IOERR_SHMMAP: zVal = "SQLITE_IOERR_SHMMAP"; break;
2621b1f30bbSdrh case SQLITE_IOERR_SEEK: zVal = "SQLITE_IOERR_SEEK"; break;
2631b1f30bbSdrh case SQLITE_IOERR_GETTEMPPATH: zVal = "SQLITE_IOERR_GETTEMPPATH"; break;
2641b1f30bbSdrh case SQLITE_IOERR_CONVPATH: zVal = "SQLITE_IOERR_CONVPATH"; break;
2653fee8a63Sdrh case SQLITE_READONLY_DBMOVED: zVal = "SQLITE_READONLY_DBMOVED"; break;
26697ae8ffbSdrh case SQLITE_LOCKED_SHAREDCACHE: zVal = "SQLITE_LOCKED_SHAREDCACHE"; break;
26797ae8ffbSdrh case SQLITE_BUSY_RECOVERY: zVal = "SQLITE_BUSY_RECOVERY"; break;
26897ae8ffbSdrh case SQLITE_CANTOPEN_NOTEMPDIR: zVal = "SQLITE_CANTOPEN_NOTEMPDIR"; break;
26997ae8ffbSdrh default: {
27097ae8ffbSdrh sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc);
27197ae8ffbSdrh zVal = zBuf;
27297ae8ffbSdrh break;
27397ae8ffbSdrh }
27497ae8ffbSdrh }
27597ae8ffbSdrh vfstrace_printf(pInfo, zFormat, zVal);
27697ae8ffbSdrh }
27797ae8ffbSdrh
27897ae8ffbSdrh /*
2792f8ebddeSdrh ** Append to a buffer.
2802f8ebddeSdrh */
strappend(char * z,int * pI,const char * zAppend)2812f8ebddeSdrh static void strappend(char *z, int *pI, const char *zAppend){
2822f8ebddeSdrh int i = *pI;
2832f8ebddeSdrh while( zAppend[0] ){ z[i++] = *(zAppend++); }
2842f8ebddeSdrh z[i] = 0;
2852f8ebddeSdrh *pI = i;
2862f8ebddeSdrh }
2872f8ebddeSdrh
2882f8ebddeSdrh /*
28997ae8ffbSdrh ** Close an vfstrace-file.
29097ae8ffbSdrh */
vfstraceClose(sqlite3_file * pFile)29197ae8ffbSdrh static int vfstraceClose(sqlite3_file *pFile){
29297ae8ffbSdrh vfstrace_file *p = (vfstrace_file *)pFile;
29397ae8ffbSdrh vfstrace_info *pInfo = p->pInfo;
29497ae8ffbSdrh int rc;
29597ae8ffbSdrh vfstrace_printf(pInfo, "%s.xClose(%s)", pInfo->zVfsName, p->zFName);
29697ae8ffbSdrh rc = p->pReal->pMethods->xClose(p->pReal);
29797ae8ffbSdrh vfstrace_print_errcode(pInfo, " -> %s\n", rc);
29897ae8ffbSdrh if( rc==SQLITE_OK ){
29997ae8ffbSdrh sqlite3_free((void*)p->base.pMethods);
30097ae8ffbSdrh p->base.pMethods = 0;
30197ae8ffbSdrh }
30297ae8ffbSdrh return rc;
30397ae8ffbSdrh }
30497ae8ffbSdrh
30597ae8ffbSdrh /*
30697ae8ffbSdrh ** Read data from an vfstrace-file.
30797ae8ffbSdrh */
vfstraceRead(sqlite3_file * pFile,void * zBuf,int iAmt,sqlite_int64 iOfst)30897ae8ffbSdrh static int vfstraceRead(
30997ae8ffbSdrh sqlite3_file *pFile,
31097ae8ffbSdrh void *zBuf,
31197ae8ffbSdrh int iAmt,
31297ae8ffbSdrh sqlite_int64 iOfst
31397ae8ffbSdrh ){
31497ae8ffbSdrh vfstrace_file *p = (vfstrace_file *)pFile;
31597ae8ffbSdrh vfstrace_info *pInfo = p->pInfo;
31697ae8ffbSdrh int rc;
3172f8ebddeSdrh vfstrace_printf(pInfo, "%s.xRead(%s,n=%d,ofst=%lld)",
3182f8ebddeSdrh pInfo->zVfsName, p->zFName, iAmt, iOfst);
31997ae8ffbSdrh rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
32097ae8ffbSdrh vfstrace_print_errcode(pInfo, " -> %s\n", rc);
32197ae8ffbSdrh return rc;
32297ae8ffbSdrh }
32397ae8ffbSdrh
32497ae8ffbSdrh /*
32597ae8ffbSdrh ** Write data to an vfstrace-file.
32697ae8ffbSdrh */
vfstraceWrite(sqlite3_file * pFile,const void * zBuf,int iAmt,sqlite_int64 iOfst)32797ae8ffbSdrh static int vfstraceWrite(
32897ae8ffbSdrh sqlite3_file *pFile,
32997ae8ffbSdrh const void *zBuf,
33097ae8ffbSdrh int iAmt,
33197ae8ffbSdrh sqlite_int64 iOfst
33297ae8ffbSdrh ){
33397ae8ffbSdrh vfstrace_file *p = (vfstrace_file *)pFile;
33497ae8ffbSdrh vfstrace_info *pInfo = p->pInfo;
33597ae8ffbSdrh int rc;
3362f8ebddeSdrh vfstrace_printf(pInfo, "%s.xWrite(%s,n=%d,ofst=%lld)",
3372f8ebddeSdrh pInfo->zVfsName, p->zFName, iAmt, iOfst);
33897ae8ffbSdrh rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
33997ae8ffbSdrh vfstrace_print_errcode(pInfo, " -> %s\n", rc);
34097ae8ffbSdrh return rc;
34197ae8ffbSdrh }
34297ae8ffbSdrh
34397ae8ffbSdrh /*
34497ae8ffbSdrh ** Truncate an vfstrace-file.
34597ae8ffbSdrh */
vfstraceTruncate(sqlite3_file * pFile,sqlite_int64 size)34697ae8ffbSdrh static int vfstraceTruncate(sqlite3_file *pFile, sqlite_int64 size){
34797ae8ffbSdrh vfstrace_file *p = (vfstrace_file *)pFile;
34897ae8ffbSdrh vfstrace_info *pInfo = p->pInfo;
34997ae8ffbSdrh int rc;
35097ae8ffbSdrh vfstrace_printf(pInfo, "%s.xTruncate(%s,%lld)", pInfo->zVfsName, p->zFName,
35197ae8ffbSdrh size);
35297ae8ffbSdrh rc = p->pReal->pMethods->xTruncate(p->pReal, size);
35397ae8ffbSdrh vfstrace_printf(pInfo, " -> %d\n", rc);
35497ae8ffbSdrh return rc;
35597ae8ffbSdrh }
35697ae8ffbSdrh
35797ae8ffbSdrh /*
35897ae8ffbSdrh ** Sync an vfstrace-file.
35997ae8ffbSdrh */
vfstraceSync(sqlite3_file * pFile,int flags)36097ae8ffbSdrh static int vfstraceSync(sqlite3_file *pFile, int flags){
36197ae8ffbSdrh vfstrace_file *p = (vfstrace_file *)pFile;
36297ae8ffbSdrh vfstrace_info *pInfo = p->pInfo;
36397ae8ffbSdrh int rc;
3642f8ebddeSdrh int i;
3652f8ebddeSdrh char zBuf[100];
3662f8ebddeSdrh memcpy(zBuf, "|0", 3);
3672f8ebddeSdrh i = 0;
3682f8ebddeSdrh if( flags & SQLITE_SYNC_FULL ) strappend(zBuf, &i, "|FULL");
3692f8ebddeSdrh else if( flags & SQLITE_SYNC_NORMAL ) strappend(zBuf, &i, "|NORMAL");
3702f8ebddeSdrh if( flags & SQLITE_SYNC_DATAONLY ) strappend(zBuf, &i, "|DATAONLY");
3712f8ebddeSdrh if( flags & ~(SQLITE_SYNC_FULL|SQLITE_SYNC_DATAONLY) ){
3722f8ebddeSdrh sqlite3_snprintf(sizeof(zBuf)-i, &zBuf[i], "|0x%x", flags);
3732f8ebddeSdrh }
3742f8ebddeSdrh vfstrace_printf(pInfo, "%s.xSync(%s,%s)", pInfo->zVfsName, p->zFName,
3752f8ebddeSdrh &zBuf[1]);
37697ae8ffbSdrh rc = p->pReal->pMethods->xSync(p->pReal, flags);
37797ae8ffbSdrh vfstrace_printf(pInfo, " -> %d\n", rc);
37897ae8ffbSdrh return rc;
37997ae8ffbSdrh }
38097ae8ffbSdrh
38197ae8ffbSdrh /*
38297ae8ffbSdrh ** Return the current file-size of an vfstrace-file.
38397ae8ffbSdrh */
vfstraceFileSize(sqlite3_file * pFile,sqlite_int64 * pSize)38497ae8ffbSdrh static int vfstraceFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
38597ae8ffbSdrh vfstrace_file *p = (vfstrace_file *)pFile;
38697ae8ffbSdrh vfstrace_info *pInfo = p->pInfo;
38797ae8ffbSdrh int rc;
38897ae8ffbSdrh vfstrace_printf(pInfo, "%s.xFileSize(%s)", pInfo->zVfsName, p->zFName);
38997ae8ffbSdrh rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
39097ae8ffbSdrh vfstrace_print_errcode(pInfo, " -> %s,", rc);
39197ae8ffbSdrh vfstrace_printf(pInfo, " size=%lld\n", *pSize);
39297ae8ffbSdrh return rc;
39397ae8ffbSdrh }
39497ae8ffbSdrh
39597ae8ffbSdrh /*
3962f8ebddeSdrh ** Return the name of a lock.
3972f8ebddeSdrh */
lockName(int eLock)3982f8ebddeSdrh static const char *lockName(int eLock){
3992f8ebddeSdrh const char *azLockNames[] = {
4002f8ebddeSdrh "NONE", "SHARED", "RESERVED", "PENDING", "EXCLUSIVE"
4012f8ebddeSdrh };
4022f8ebddeSdrh if( eLock<0 || eLock>=sizeof(azLockNames)/sizeof(azLockNames[0]) ){
4032f8ebddeSdrh return "???";
4042f8ebddeSdrh }else{
4052f8ebddeSdrh return azLockNames[eLock];
4062f8ebddeSdrh }
4072f8ebddeSdrh }
4082f8ebddeSdrh
4092f8ebddeSdrh /*
41097ae8ffbSdrh ** Lock an vfstrace-file.
41197ae8ffbSdrh */
vfstraceLock(sqlite3_file * pFile,int eLock)41297ae8ffbSdrh static int vfstraceLock(sqlite3_file *pFile, int eLock){
41397ae8ffbSdrh vfstrace_file *p = (vfstrace_file *)pFile;
41497ae8ffbSdrh vfstrace_info *pInfo = p->pInfo;
41597ae8ffbSdrh int rc;
4162f8ebddeSdrh vfstrace_printf(pInfo, "%s.xLock(%s,%s)", pInfo->zVfsName, p->zFName,
4172f8ebddeSdrh lockName(eLock));
41897ae8ffbSdrh rc = p->pReal->pMethods->xLock(p->pReal, eLock);
41997ae8ffbSdrh vfstrace_print_errcode(pInfo, " -> %s\n", rc);
42097ae8ffbSdrh return rc;
42197ae8ffbSdrh }
42297ae8ffbSdrh
42397ae8ffbSdrh /*
42497ae8ffbSdrh ** Unlock an vfstrace-file.
42597ae8ffbSdrh */
vfstraceUnlock(sqlite3_file * pFile,int eLock)42697ae8ffbSdrh static int vfstraceUnlock(sqlite3_file *pFile, int eLock){
42797ae8ffbSdrh vfstrace_file *p = (vfstrace_file *)pFile;
42897ae8ffbSdrh vfstrace_info *pInfo = p->pInfo;
42997ae8ffbSdrh int rc;
4302f8ebddeSdrh vfstrace_printf(pInfo, "%s.xUnlock(%s,%s)", pInfo->zVfsName, p->zFName,
4312f8ebddeSdrh lockName(eLock));
43297ae8ffbSdrh rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
43397ae8ffbSdrh vfstrace_print_errcode(pInfo, " -> %s\n", rc);
43497ae8ffbSdrh return rc;
43597ae8ffbSdrh }
43697ae8ffbSdrh
43797ae8ffbSdrh /*
43897ae8ffbSdrh ** Check if another file-handle holds a RESERVED lock on an vfstrace-file.
43997ae8ffbSdrh */
vfstraceCheckReservedLock(sqlite3_file * pFile,int * pResOut)44097ae8ffbSdrh static int vfstraceCheckReservedLock(sqlite3_file *pFile, int *pResOut){
44197ae8ffbSdrh vfstrace_file *p = (vfstrace_file *)pFile;
44297ae8ffbSdrh vfstrace_info *pInfo = p->pInfo;
44397ae8ffbSdrh int rc;
44497ae8ffbSdrh vfstrace_printf(pInfo, "%s.xCheckReservedLock(%s,%d)",
44597ae8ffbSdrh pInfo->zVfsName, p->zFName);
44697ae8ffbSdrh rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
44797ae8ffbSdrh vfstrace_print_errcode(pInfo, " -> %s", rc);
44897ae8ffbSdrh vfstrace_printf(pInfo, ", out=%d\n", *pResOut);
44997ae8ffbSdrh return rc;
45097ae8ffbSdrh }
45197ae8ffbSdrh
45297ae8ffbSdrh /*
45397ae8ffbSdrh ** File control method. For custom operations on an vfstrace-file.
45497ae8ffbSdrh */
vfstraceFileControl(sqlite3_file * pFile,int op,void * pArg)45597ae8ffbSdrh static int vfstraceFileControl(sqlite3_file *pFile, int op, void *pArg){
45697ae8ffbSdrh vfstrace_file *p = (vfstrace_file *)pFile;
45797ae8ffbSdrh vfstrace_info *pInfo = p->pInfo;
45897ae8ffbSdrh int rc;
4592f8ebddeSdrh char zBuf[100];
4602f8ebddeSdrh char *zOp;
4612f8ebddeSdrh switch( op ){
4622f8ebddeSdrh case SQLITE_FCNTL_LOCKSTATE: zOp = "LOCKSTATE"; break;
4632f8ebddeSdrh case SQLITE_GET_LOCKPROXYFILE: zOp = "GET_LOCKPROXYFILE"; break;
4642f8ebddeSdrh case SQLITE_SET_LOCKPROXYFILE: zOp = "SET_LOCKPROXYFILE"; break;
4652f8ebddeSdrh case SQLITE_LAST_ERRNO: zOp = "LAST_ERRNO"; break;
4662f8ebddeSdrh case SQLITE_FCNTL_SIZE_HINT: {
4672f8ebddeSdrh sqlite3_snprintf(sizeof(zBuf), zBuf, "SIZE_HINT,%lld",
4682f8ebddeSdrh *(sqlite3_int64*)pArg);
4692f8ebddeSdrh zOp = zBuf;
4702f8ebddeSdrh break;
4712f8ebddeSdrh }
4722f8ebddeSdrh case SQLITE_FCNTL_CHUNK_SIZE: {
4732f8ebddeSdrh sqlite3_snprintf(sizeof(zBuf), zBuf, "CHUNK_SIZE,%d", *(int*)pArg);
4742f8ebddeSdrh zOp = zBuf;
4752f8ebddeSdrh break;
4762f8ebddeSdrh }
4772f8ebddeSdrh case SQLITE_FCNTL_FILE_POINTER: zOp = "FILE_POINTER"; break;
4782f8ebddeSdrh case SQLITE_FCNTL_SYNC_OMITTED: zOp = "SYNC_OMITTED"; break;
479de60fc2dSdrh case SQLITE_FCNTL_WIN32_AV_RETRY: zOp = "WIN32_AV_RETRY"; break;
480de60fc2dSdrh case SQLITE_FCNTL_PERSIST_WAL: zOp = "PERSIST_WAL"; break;
481de60fc2dSdrh case SQLITE_FCNTL_OVERWRITE: zOp = "OVERWRITE"; break;
482de60fc2dSdrh case SQLITE_FCNTL_VFSNAME: zOp = "VFSNAME"; break;
483696b33e6Sdrh case SQLITE_FCNTL_TEMPFILENAME: zOp = "TEMPFILENAME"; break;
4842f8ebddeSdrh case 0xca093fa0: zOp = "DB_UNCHANGED"; break;
48506fd5d63Sdrh case SQLITE_FCNTL_PRAGMA: {
48606fd5d63Sdrh const char *const* a = (const char*const*)pArg;
4873fa97302Sdrh sqlite3_snprintf(sizeof(zBuf), zBuf, "PRAGMA,[%s,%s]",a[1],a[2]);
48806fd5d63Sdrh zOp = zBuf;
48906fd5d63Sdrh break;
49006fd5d63Sdrh }
4912f8ebddeSdrh default: {
4922f8ebddeSdrh sqlite3_snprintf(sizeof zBuf, zBuf, "%d", op);
4932f8ebddeSdrh zOp = zBuf;
4942f8ebddeSdrh break;
4952f8ebddeSdrh }
4962f8ebddeSdrh }
4972f8ebddeSdrh vfstrace_printf(pInfo, "%s.xFileControl(%s,%s)",
4982f8ebddeSdrh pInfo->zVfsName, p->zFName, zOp);
49997ae8ffbSdrh rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
50097ae8ffbSdrh vfstrace_print_errcode(pInfo, " -> %s\n", rc);
501de60fc2dSdrh if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
502de60fc2dSdrh *(char**)pArg = sqlite3_mprintf("vfstrace.%s/%z",
503de60fc2dSdrh pInfo->zVfsName, *(char**)pArg);
504de60fc2dSdrh }
505696b33e6Sdrh if( (op==SQLITE_FCNTL_PRAGMA || op==SQLITE_FCNTL_TEMPFILENAME)
506696b33e6Sdrh && rc==SQLITE_OK && *(char**)pArg ){
5073fa97302Sdrh vfstrace_printf(pInfo, "%s.xFileControl(%s,%s) returns %s",
50849dc66dfSdrh pInfo->zVfsName, p->zFName, zOp, *(char**)pArg);
5093fa97302Sdrh }
51097ae8ffbSdrh return rc;
51197ae8ffbSdrh }
51297ae8ffbSdrh
51397ae8ffbSdrh /*
51497ae8ffbSdrh ** Return the sector-size in bytes for an vfstrace-file.
51597ae8ffbSdrh */
vfstraceSectorSize(sqlite3_file * pFile)51697ae8ffbSdrh static int vfstraceSectorSize(sqlite3_file *pFile){
51797ae8ffbSdrh vfstrace_file *p = (vfstrace_file *)pFile;
51897ae8ffbSdrh vfstrace_info *pInfo = p->pInfo;
51997ae8ffbSdrh int rc;
52097ae8ffbSdrh vfstrace_printf(pInfo, "%s.xSectorSize(%s)", pInfo->zVfsName, p->zFName);
52197ae8ffbSdrh rc = p->pReal->pMethods->xSectorSize(p->pReal);
52297ae8ffbSdrh vfstrace_printf(pInfo, " -> %d\n", rc);
52397ae8ffbSdrh return rc;
52497ae8ffbSdrh }
52597ae8ffbSdrh
52697ae8ffbSdrh /*
52797ae8ffbSdrh ** Return the device characteristic flags supported by an vfstrace-file.
52897ae8ffbSdrh */
vfstraceDeviceCharacteristics(sqlite3_file * pFile)52997ae8ffbSdrh static int vfstraceDeviceCharacteristics(sqlite3_file *pFile){
53097ae8ffbSdrh vfstrace_file *p = (vfstrace_file *)pFile;
53197ae8ffbSdrh vfstrace_info *pInfo = p->pInfo;
53297ae8ffbSdrh int rc;
53397ae8ffbSdrh vfstrace_printf(pInfo, "%s.xDeviceCharacteristics(%s)",
53497ae8ffbSdrh pInfo->zVfsName, p->zFName);
53597ae8ffbSdrh rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
53697ae8ffbSdrh vfstrace_printf(pInfo, " -> 0x%08x\n", rc);
53797ae8ffbSdrh return rc;
53897ae8ffbSdrh }
53997ae8ffbSdrh
54097ae8ffbSdrh /*
54197ae8ffbSdrh ** Shared-memory operations.
54297ae8ffbSdrh */
vfstraceShmLock(sqlite3_file * pFile,int ofst,int n,int flags)54397ae8ffbSdrh static int vfstraceShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
54497ae8ffbSdrh vfstrace_file *p = (vfstrace_file *)pFile;
54597ae8ffbSdrh vfstrace_info *pInfo = p->pInfo;
54697ae8ffbSdrh int rc;
5472f8ebddeSdrh char zLck[100];
5482f8ebddeSdrh int i = 0;
5492f8ebddeSdrh memcpy(zLck, "|0", 3);
5502f8ebddeSdrh if( flags & SQLITE_SHM_UNLOCK ) strappend(zLck, &i, "|UNLOCK");
5512f8ebddeSdrh if( flags & SQLITE_SHM_LOCK ) strappend(zLck, &i, "|LOCK");
5522f8ebddeSdrh if( flags & SQLITE_SHM_SHARED ) strappend(zLck, &i, "|SHARED");
5532f8ebddeSdrh if( flags & SQLITE_SHM_EXCLUSIVE ) strappend(zLck, &i, "|EXCLUSIVE");
5542f8ebddeSdrh if( flags & ~(0xf) ){
5552f8ebddeSdrh sqlite3_snprintf(sizeof(zLck)-i, &zLck[i], "|0x%x", flags);
5562f8ebddeSdrh }
5572f8ebddeSdrh vfstrace_printf(pInfo, "%s.xShmLock(%s,ofst=%d,n=%d,%s)",
5582f8ebddeSdrh pInfo->zVfsName, p->zFName, ofst, n, &zLck[1]);
55997ae8ffbSdrh rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
56097ae8ffbSdrh vfstrace_print_errcode(pInfo, " -> %s\n", rc);
56197ae8ffbSdrh return rc;
56297ae8ffbSdrh }
vfstraceShmMap(sqlite3_file * pFile,int iRegion,int szRegion,int isWrite,void volatile ** pp)56397ae8ffbSdrh static int vfstraceShmMap(
56497ae8ffbSdrh sqlite3_file *pFile,
56597ae8ffbSdrh int iRegion,
56697ae8ffbSdrh int szRegion,
56797ae8ffbSdrh int isWrite,
56897ae8ffbSdrh void volatile **pp
56997ae8ffbSdrh ){
57097ae8ffbSdrh vfstrace_file *p = (vfstrace_file *)pFile;
57197ae8ffbSdrh vfstrace_info *pInfo = p->pInfo;
57297ae8ffbSdrh int rc;
57397ae8ffbSdrh vfstrace_printf(pInfo, "%s.xShmMap(%s,iRegion=%d,szRegion=%d,isWrite=%d,*)",
57497ae8ffbSdrh pInfo->zVfsName, p->zFName, iRegion, szRegion, isWrite);
57597ae8ffbSdrh rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
57697ae8ffbSdrh vfstrace_print_errcode(pInfo, " -> %s\n", rc);
57797ae8ffbSdrh return rc;
57897ae8ffbSdrh }
vfstraceShmBarrier(sqlite3_file * pFile)57997ae8ffbSdrh static void vfstraceShmBarrier(sqlite3_file *pFile){
58097ae8ffbSdrh vfstrace_file *p = (vfstrace_file *)pFile;
58197ae8ffbSdrh vfstrace_info *pInfo = p->pInfo;
58297ae8ffbSdrh vfstrace_printf(pInfo, "%s.xShmBarrier(%s)\n", pInfo->zVfsName, p->zFName);
58397ae8ffbSdrh p->pReal->pMethods->xShmBarrier(p->pReal);
58497ae8ffbSdrh }
vfstraceShmUnmap(sqlite3_file * pFile,int delFlag)58597ae8ffbSdrh static int vfstraceShmUnmap(sqlite3_file *pFile, int delFlag){
58697ae8ffbSdrh vfstrace_file *p = (vfstrace_file *)pFile;
58797ae8ffbSdrh vfstrace_info *pInfo = p->pInfo;
58897ae8ffbSdrh int rc;
58997ae8ffbSdrh vfstrace_printf(pInfo, "%s.xShmUnmap(%s,delFlag=%d)",
59097ae8ffbSdrh pInfo->zVfsName, p->zFName, delFlag);
59197ae8ffbSdrh rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
59297ae8ffbSdrh vfstrace_print_errcode(pInfo, " -> %s\n", rc);
59397ae8ffbSdrh return rc;
59497ae8ffbSdrh }
59597ae8ffbSdrh
59697ae8ffbSdrh
59797ae8ffbSdrh
59897ae8ffbSdrh /*
59997ae8ffbSdrh ** Open an vfstrace file handle.
60097ae8ffbSdrh */
vfstraceOpen(sqlite3_vfs * pVfs,const char * zName,sqlite3_file * pFile,int flags,int * pOutFlags)60197ae8ffbSdrh static int vfstraceOpen(
60297ae8ffbSdrh sqlite3_vfs *pVfs,
60397ae8ffbSdrh const char *zName,
60497ae8ffbSdrh sqlite3_file *pFile,
60597ae8ffbSdrh int flags,
60697ae8ffbSdrh int *pOutFlags
60797ae8ffbSdrh ){
60897ae8ffbSdrh int rc;
60997ae8ffbSdrh vfstrace_file *p = (vfstrace_file *)pFile;
61097ae8ffbSdrh vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
61197ae8ffbSdrh sqlite3_vfs *pRoot = pInfo->pRootVfs;
61297ae8ffbSdrh p->pInfo = pInfo;
6132f8ebddeSdrh p->zFName = zName ? fileTail(zName) : "<temp>";
61497ae8ffbSdrh p->pReal = (sqlite3_file *)&p[1];
61597ae8ffbSdrh rc = pRoot->xOpen(pRoot, zName, p->pReal, flags, pOutFlags);
61697ae8ffbSdrh vfstrace_printf(pInfo, "%s.xOpen(%s,flags=0x%x)",
61797ae8ffbSdrh pInfo->zVfsName, p->zFName, flags);
61897ae8ffbSdrh if( p->pReal->pMethods ){
61997ae8ffbSdrh sqlite3_io_methods *pNew = sqlite3_malloc( sizeof(*pNew) );
62097ae8ffbSdrh const sqlite3_io_methods *pSub = p->pReal->pMethods;
62197ae8ffbSdrh memset(pNew, 0, sizeof(*pNew));
62297ae8ffbSdrh pNew->iVersion = pSub->iVersion;
62397ae8ffbSdrh pNew->xClose = vfstraceClose;
62497ae8ffbSdrh pNew->xRead = vfstraceRead;
62597ae8ffbSdrh pNew->xWrite = vfstraceWrite;
62697ae8ffbSdrh pNew->xTruncate = vfstraceTruncate;
62797ae8ffbSdrh pNew->xSync = vfstraceSync;
62897ae8ffbSdrh pNew->xFileSize = vfstraceFileSize;
62997ae8ffbSdrh pNew->xLock = vfstraceLock;
63097ae8ffbSdrh pNew->xUnlock = vfstraceUnlock;
63197ae8ffbSdrh pNew->xCheckReservedLock = vfstraceCheckReservedLock;
63297ae8ffbSdrh pNew->xFileControl = vfstraceFileControl;
63397ae8ffbSdrh pNew->xSectorSize = vfstraceSectorSize;
63497ae8ffbSdrh pNew->xDeviceCharacteristics = vfstraceDeviceCharacteristics;
63597ae8ffbSdrh if( pNew->iVersion>=2 ){
63697ae8ffbSdrh pNew->xShmMap = pSub->xShmMap ? vfstraceShmMap : 0;
63797ae8ffbSdrh pNew->xShmLock = pSub->xShmLock ? vfstraceShmLock : 0;
63897ae8ffbSdrh pNew->xShmBarrier = pSub->xShmBarrier ? vfstraceShmBarrier : 0;
63997ae8ffbSdrh pNew->xShmUnmap = pSub->xShmUnmap ? vfstraceShmUnmap : 0;
64097ae8ffbSdrh }
64197ae8ffbSdrh pFile->pMethods = pNew;
64297ae8ffbSdrh }
64397ae8ffbSdrh vfstrace_print_errcode(pInfo, " -> %s", rc);
6442f8ebddeSdrh if( pOutFlags ){
64597ae8ffbSdrh vfstrace_printf(pInfo, ", outFlags=0x%x\n", *pOutFlags);
6462f8ebddeSdrh }else{
6472f8ebddeSdrh vfstrace_printf(pInfo, "\n");
6482f8ebddeSdrh }
64997ae8ffbSdrh return rc;
65097ae8ffbSdrh }
65197ae8ffbSdrh
65297ae8ffbSdrh /*
65397ae8ffbSdrh ** Delete the file located at zPath. If the dirSync argument is true,
65497ae8ffbSdrh ** ensure the file-system modifications are synced to disk before
65597ae8ffbSdrh ** returning.
65697ae8ffbSdrh */
vfstraceDelete(sqlite3_vfs * pVfs,const char * zPath,int dirSync)65797ae8ffbSdrh static int vfstraceDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
65897ae8ffbSdrh vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
65997ae8ffbSdrh sqlite3_vfs *pRoot = pInfo->pRootVfs;
66097ae8ffbSdrh int rc;
66197ae8ffbSdrh vfstrace_printf(pInfo, "%s.xDelete(\"%s\",%d)",
66297ae8ffbSdrh pInfo->zVfsName, zPath, dirSync);
66397ae8ffbSdrh rc = pRoot->xDelete(pRoot, zPath, dirSync);
66497ae8ffbSdrh vfstrace_print_errcode(pInfo, " -> %s\n", rc);
66597ae8ffbSdrh return rc;
66697ae8ffbSdrh }
66797ae8ffbSdrh
66897ae8ffbSdrh /*
66997ae8ffbSdrh ** Test for access permissions. Return true if the requested permission
67097ae8ffbSdrh ** is available, or false otherwise.
67197ae8ffbSdrh */
vfstraceAccess(sqlite3_vfs * pVfs,const char * zPath,int flags,int * pResOut)67297ae8ffbSdrh static int vfstraceAccess(
67397ae8ffbSdrh sqlite3_vfs *pVfs,
67497ae8ffbSdrh const char *zPath,
67597ae8ffbSdrh int flags,
67697ae8ffbSdrh int *pResOut
67797ae8ffbSdrh ){
67897ae8ffbSdrh vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
67997ae8ffbSdrh sqlite3_vfs *pRoot = pInfo->pRootVfs;
68097ae8ffbSdrh int rc;
681*65e6b0ddSdrh vfstrace_printf(pInfo, "%s.xAccess(\"%s\",%d)",
68297ae8ffbSdrh pInfo->zVfsName, zPath, flags);
68397ae8ffbSdrh rc = pRoot->xAccess(pRoot, zPath, flags, pResOut);
68497ae8ffbSdrh vfstrace_print_errcode(pInfo, " -> %s", rc);
68597ae8ffbSdrh vfstrace_printf(pInfo, ", out=%d\n", *pResOut);
68697ae8ffbSdrh return rc;
68797ae8ffbSdrh }
68897ae8ffbSdrh
68997ae8ffbSdrh /*
69097ae8ffbSdrh ** Populate buffer zOut with the full canonical pathname corresponding
69197ae8ffbSdrh ** to the pathname in zPath. zOut is guaranteed to point to a buffer
69297ae8ffbSdrh ** of at least (DEVSYM_MAX_PATHNAME+1) bytes.
69397ae8ffbSdrh */
vfstraceFullPathname(sqlite3_vfs * pVfs,const char * zPath,int nOut,char * zOut)69497ae8ffbSdrh static int vfstraceFullPathname(
69597ae8ffbSdrh sqlite3_vfs *pVfs,
69697ae8ffbSdrh const char *zPath,
69797ae8ffbSdrh int nOut,
69897ae8ffbSdrh char *zOut
69997ae8ffbSdrh ){
70097ae8ffbSdrh vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
70197ae8ffbSdrh sqlite3_vfs *pRoot = pInfo->pRootVfs;
70297ae8ffbSdrh int rc;
70397ae8ffbSdrh vfstrace_printf(pInfo, "%s.xFullPathname(\"%s\")",
70497ae8ffbSdrh pInfo->zVfsName, zPath);
70597ae8ffbSdrh rc = pRoot->xFullPathname(pRoot, zPath, nOut, zOut);
70697ae8ffbSdrh vfstrace_print_errcode(pInfo, " -> %s", rc);
70797ae8ffbSdrh vfstrace_printf(pInfo, ", out=\"%.*s\"\n", nOut, zOut);
70897ae8ffbSdrh return rc;
70997ae8ffbSdrh }
71097ae8ffbSdrh
71197ae8ffbSdrh /*
71297ae8ffbSdrh ** Open the dynamic library located at zPath and return a handle.
71397ae8ffbSdrh */
vfstraceDlOpen(sqlite3_vfs * pVfs,const char * zPath)71497ae8ffbSdrh static void *vfstraceDlOpen(sqlite3_vfs *pVfs, const char *zPath){
71597ae8ffbSdrh vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
71697ae8ffbSdrh sqlite3_vfs *pRoot = pInfo->pRootVfs;
71797ae8ffbSdrh vfstrace_printf(pInfo, "%s.xDlOpen(\"%s\")\n", pInfo->zVfsName, zPath);
71897ae8ffbSdrh return pRoot->xDlOpen(pRoot, zPath);
71997ae8ffbSdrh }
72097ae8ffbSdrh
72197ae8ffbSdrh /*
72297ae8ffbSdrh ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
72397ae8ffbSdrh ** utf-8 string describing the most recent error encountered associated
72497ae8ffbSdrh ** with dynamic libraries.
72597ae8ffbSdrh */
vfstraceDlError(sqlite3_vfs * pVfs,int nByte,char * zErrMsg)72697ae8ffbSdrh static void vfstraceDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
72797ae8ffbSdrh vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
72897ae8ffbSdrh sqlite3_vfs *pRoot = pInfo->pRootVfs;
72997ae8ffbSdrh vfstrace_printf(pInfo, "%s.xDlError(%d)", pInfo->zVfsName, nByte);
73097ae8ffbSdrh pRoot->xDlError(pRoot, nByte, zErrMsg);
73197ae8ffbSdrh vfstrace_printf(pInfo, " -> \"%s\"", zErrMsg);
73297ae8ffbSdrh }
73397ae8ffbSdrh
73497ae8ffbSdrh /*
73597ae8ffbSdrh ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
73697ae8ffbSdrh */
vfstraceDlSym(sqlite3_vfs * pVfs,void * p,const char * zSym)73797ae8ffbSdrh static void (*vfstraceDlSym(sqlite3_vfs *pVfs,void *p,const char *zSym))(void){
73897ae8ffbSdrh vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
73997ae8ffbSdrh sqlite3_vfs *pRoot = pInfo->pRootVfs;
74097ae8ffbSdrh vfstrace_printf(pInfo, "%s.xDlSym(\"%s\")\n", pInfo->zVfsName, zSym);
74197ae8ffbSdrh return pRoot->xDlSym(pRoot, p, zSym);
74297ae8ffbSdrh }
74397ae8ffbSdrh
74497ae8ffbSdrh /*
74597ae8ffbSdrh ** Close the dynamic library handle pHandle.
74697ae8ffbSdrh */
vfstraceDlClose(sqlite3_vfs * pVfs,void * pHandle)74797ae8ffbSdrh static void vfstraceDlClose(sqlite3_vfs *pVfs, void *pHandle){
74897ae8ffbSdrh vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
74997ae8ffbSdrh sqlite3_vfs *pRoot = pInfo->pRootVfs;
75097ae8ffbSdrh vfstrace_printf(pInfo, "%s.xDlOpen()\n", pInfo->zVfsName);
75197ae8ffbSdrh pRoot->xDlClose(pRoot, pHandle);
75297ae8ffbSdrh }
75397ae8ffbSdrh
75497ae8ffbSdrh /*
75597ae8ffbSdrh ** Populate the buffer pointed to by zBufOut with nByte bytes of
75697ae8ffbSdrh ** random data.
75797ae8ffbSdrh */
vfstraceRandomness(sqlite3_vfs * pVfs,int nByte,char * zBufOut)75897ae8ffbSdrh static int vfstraceRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
75997ae8ffbSdrh vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
76097ae8ffbSdrh sqlite3_vfs *pRoot = pInfo->pRootVfs;
76197ae8ffbSdrh vfstrace_printf(pInfo, "%s.xRandomness(%d)\n", pInfo->zVfsName, nByte);
76297ae8ffbSdrh return pRoot->xRandomness(pRoot, nByte, zBufOut);
76397ae8ffbSdrh }
76497ae8ffbSdrh
76597ae8ffbSdrh /*
76697ae8ffbSdrh ** Sleep for nMicro microseconds. Return the number of microseconds
76797ae8ffbSdrh ** actually slept.
76897ae8ffbSdrh */
vfstraceSleep(sqlite3_vfs * pVfs,int nMicro)76997ae8ffbSdrh static int vfstraceSleep(sqlite3_vfs *pVfs, int nMicro){
77097ae8ffbSdrh vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
77197ae8ffbSdrh sqlite3_vfs *pRoot = pInfo->pRootVfs;
77297ae8ffbSdrh return pRoot->xSleep(pRoot, nMicro);
77397ae8ffbSdrh }
77497ae8ffbSdrh
77597ae8ffbSdrh /*
77697ae8ffbSdrh ** Return the current time as a Julian Day number in *pTimeOut.
77797ae8ffbSdrh */
vfstraceCurrentTime(sqlite3_vfs * pVfs,double * pTimeOut)77897ae8ffbSdrh static int vfstraceCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
77997ae8ffbSdrh vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
78097ae8ffbSdrh sqlite3_vfs *pRoot = pInfo->pRootVfs;
78197ae8ffbSdrh return pRoot->xCurrentTime(pRoot, pTimeOut);
78297ae8ffbSdrh }
vfstraceCurrentTimeInt64(sqlite3_vfs * pVfs,sqlite3_int64 * pTimeOut)78397ae8ffbSdrh static int vfstraceCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
78497ae8ffbSdrh vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
78597ae8ffbSdrh sqlite3_vfs *pRoot = pInfo->pRootVfs;
78697ae8ffbSdrh return pRoot->xCurrentTimeInt64(pRoot, pTimeOut);
78797ae8ffbSdrh }
78897ae8ffbSdrh
78997ae8ffbSdrh /*
79097ae8ffbSdrh ** Return th3 emost recent error code and message
79197ae8ffbSdrh */
vfstraceGetLastError(sqlite3_vfs * pVfs,int iErr,char * zErr)79297ae8ffbSdrh static int vfstraceGetLastError(sqlite3_vfs *pVfs, int iErr, char *zErr){
79397ae8ffbSdrh vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
79497ae8ffbSdrh sqlite3_vfs *pRoot = pInfo->pRootVfs;
79597ae8ffbSdrh return pRoot->xGetLastError(pRoot, iErr, zErr);
79697ae8ffbSdrh }
79797ae8ffbSdrh
79897ae8ffbSdrh /*
79997ae8ffbSdrh ** Override system calls.
80097ae8ffbSdrh */
vfstraceSetSystemCall(sqlite3_vfs * pVfs,const char * zName,sqlite3_syscall_ptr pFunc)80197ae8ffbSdrh static int vfstraceSetSystemCall(
80297ae8ffbSdrh sqlite3_vfs *pVfs,
80397ae8ffbSdrh const char *zName,
804943bf018Sdrh sqlite3_syscall_ptr pFunc
80597ae8ffbSdrh ){
80697ae8ffbSdrh vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
80797ae8ffbSdrh sqlite3_vfs *pRoot = pInfo->pRootVfs;
80897ae8ffbSdrh return pRoot->xSetSystemCall(pRoot, zName, pFunc);
80997ae8ffbSdrh }
vfstraceGetSystemCall(sqlite3_vfs * pVfs,const char * zName)810943bf018Sdrh static sqlite3_syscall_ptr vfstraceGetSystemCall(
811943bf018Sdrh sqlite3_vfs *pVfs,
812943bf018Sdrh const char *zName
813943bf018Sdrh ){
81497ae8ffbSdrh vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
81597ae8ffbSdrh sqlite3_vfs *pRoot = pInfo->pRootVfs;
81697ae8ffbSdrh return pRoot->xGetSystemCall(pRoot, zName);
81797ae8ffbSdrh }
vfstraceNextSystemCall(sqlite3_vfs * pVfs,const char * zName)81897ae8ffbSdrh static const char *vfstraceNextSystemCall(sqlite3_vfs *pVfs, const char *zName){
81997ae8ffbSdrh vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
82097ae8ffbSdrh sqlite3_vfs *pRoot = pInfo->pRootVfs;
82197ae8ffbSdrh return pRoot->xNextSystemCall(pRoot, zName);
82297ae8ffbSdrh }
82397ae8ffbSdrh
82497ae8ffbSdrh
82597ae8ffbSdrh /*
82697ae8ffbSdrh ** Clients invoke this routine to construct a new trace-vfs shim.
82797ae8ffbSdrh **
82897ae8ffbSdrh ** Return SQLITE_OK on success.
82997ae8ffbSdrh **
83097ae8ffbSdrh ** SQLITE_NOMEM is returned in the case of a memory allocation error.
83197ae8ffbSdrh ** SQLITE_NOTFOUND is returned if zOldVfsName does not exist.
83297ae8ffbSdrh */
vfstrace_register(const char * zTraceName,const char * zOldVfsName,int (* xOut)(const char *,void *),void * pOutArg,int makeDefault)83397ae8ffbSdrh int vfstrace_register(
83497ae8ffbSdrh const char *zTraceName, /* Name of the newly constructed VFS */
83597ae8ffbSdrh const char *zOldVfsName, /* Name of the underlying VFS */
83697ae8ffbSdrh int (*xOut)(const char*,void*), /* Output routine. ex: fputs */
83797ae8ffbSdrh void *pOutArg, /* 2nd argument to xOut. ex: stderr */
83897ae8ffbSdrh int makeDefault /* True to make the new VFS the default */
83997ae8ffbSdrh ){
84097ae8ffbSdrh sqlite3_vfs *pNew;
84197ae8ffbSdrh sqlite3_vfs *pRoot;
84297ae8ffbSdrh vfstrace_info *pInfo;
84397ae8ffbSdrh int nName;
84497ae8ffbSdrh int nByte;
84597ae8ffbSdrh
84697ae8ffbSdrh pRoot = sqlite3_vfs_find(zOldVfsName);
84797ae8ffbSdrh if( pRoot==0 ) return SQLITE_NOTFOUND;
84897ae8ffbSdrh nName = strlen(zTraceName);
84997ae8ffbSdrh nByte = sizeof(*pNew) + sizeof(*pInfo) + nName + 1;
85097ae8ffbSdrh pNew = sqlite3_malloc( nByte );
85197ae8ffbSdrh if( pNew==0 ) return SQLITE_NOMEM;
85297ae8ffbSdrh memset(pNew, 0, nByte);
85397ae8ffbSdrh pInfo = (vfstrace_info*)&pNew[1];
85497ae8ffbSdrh pNew->iVersion = pRoot->iVersion;
85597ae8ffbSdrh pNew->szOsFile = pRoot->szOsFile + sizeof(vfstrace_file);
85697ae8ffbSdrh pNew->mxPathname = pRoot->mxPathname;
85797ae8ffbSdrh pNew->zName = (char*)&pInfo[1];
85897ae8ffbSdrh memcpy((char*)&pInfo[1], zTraceName, nName+1);
85997ae8ffbSdrh pNew->pAppData = pInfo;
86097ae8ffbSdrh pNew->xOpen = vfstraceOpen;
86197ae8ffbSdrh pNew->xDelete = vfstraceDelete;
86297ae8ffbSdrh pNew->xAccess = vfstraceAccess;
86397ae8ffbSdrh pNew->xFullPathname = vfstraceFullPathname;
86497ae8ffbSdrh pNew->xDlOpen = pRoot->xDlOpen==0 ? 0 : vfstraceDlOpen;
86597ae8ffbSdrh pNew->xDlError = pRoot->xDlError==0 ? 0 : vfstraceDlError;
86697ae8ffbSdrh pNew->xDlSym = pRoot->xDlSym==0 ? 0 : vfstraceDlSym;
86797ae8ffbSdrh pNew->xDlClose = pRoot->xDlClose==0 ? 0 : vfstraceDlClose;
86897ae8ffbSdrh pNew->xRandomness = vfstraceRandomness;
86997ae8ffbSdrh pNew->xSleep = vfstraceSleep;
87097ae8ffbSdrh pNew->xCurrentTime = vfstraceCurrentTime;
87197ae8ffbSdrh pNew->xGetLastError = pRoot->xGetLastError==0 ? 0 : vfstraceGetLastError;
87297ae8ffbSdrh if( pNew->iVersion>=2 ){
87397ae8ffbSdrh pNew->xCurrentTimeInt64 = pRoot->xCurrentTimeInt64==0 ? 0 :
87497ae8ffbSdrh vfstraceCurrentTimeInt64;
87597ae8ffbSdrh if( pNew->iVersion>=3 ){
87697ae8ffbSdrh pNew->xSetSystemCall = pRoot->xSetSystemCall==0 ? 0 :
87797ae8ffbSdrh vfstraceSetSystemCall;
87897ae8ffbSdrh pNew->xGetSystemCall = pRoot->xGetSystemCall==0 ? 0 :
87997ae8ffbSdrh vfstraceGetSystemCall;
88097ae8ffbSdrh pNew->xNextSystemCall = pRoot->xNextSystemCall==0 ? 0 :
88197ae8ffbSdrh vfstraceNextSystemCall;
88297ae8ffbSdrh }
88397ae8ffbSdrh }
88497ae8ffbSdrh pInfo->pRootVfs = pRoot;
88597ae8ffbSdrh pInfo->xOut = xOut;
88697ae8ffbSdrh pInfo->pOutArg = pOutArg;
88797ae8ffbSdrh pInfo->zVfsName = pNew->zName;
88897ae8ffbSdrh pInfo->pTraceVfs = pNew;
88997ae8ffbSdrh vfstrace_printf(pInfo, "%s.enabled_for(\"%s\")\n",
89097ae8ffbSdrh pInfo->zVfsName, pRoot->zName);
89197ae8ffbSdrh return sqlite3_vfs_register(pNew, makeDefault);
89297ae8ffbSdrh }
893