xref: /sqlite-3.40.0/src/test_vfstrace.c (revision 65e6b0dd)
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