dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 1 | /* |
| 2 | ** 2010 May 05 |
| 3 | ** |
| 4 | ** The author disclaims copyright to this source code. In place of |
| 5 | ** a legal notice, here is a blessing: |
| 6 | ** |
| 7 | ** May you do good and not evil. |
| 8 | ** May you find forgiveness for yourself and forgive others. |
| 9 | ** May you share freely, never taking more than you give. |
| 10 | ** |
| 11 | ****************************************************************************** |
| 12 | ** |
| 13 | */ |
| 14 | #if SQLITE_TEST /* This file is used for testing only */ |
| 15 | |
| 16 | #include "sqlite3.h" |
| 17 | #include "sqliteInt.h" |
| 18 | |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 19 | typedef struct Testvfs Testvfs; |
| 20 | typedef struct TestvfsShm TestvfsShm; |
| 21 | typedef struct TestvfsBuffer TestvfsBuffer; |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 22 | typedef struct TestvfsFile TestvfsFile; |
| 23 | |
| 24 | /* |
| 25 | ** An open file handle. |
| 26 | */ |
| 27 | struct TestvfsFile { |
| 28 | sqlite3_file base; /* Base class. Must be first */ |
| 29 | sqlite3_vfs *pVfs; /* The VFS */ |
| 30 | const char *zFilename; /* Filename as passed to xOpen() */ |
| 31 | sqlite3_file *pReal; /* The real, underlying file descriptor */ |
| 32 | Tcl_Obj *pShmId; /* Shared memory id for Tcl callbacks */ |
| 33 | TestvfsBuffer *pShm; /* Shared memory buffer */ |
drh | d9e5c4f | 2010-05-12 18:01:39 +0000 | [diff] [blame] | 34 | }; |
| 35 | |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 36 | |
| 37 | /* |
| 38 | ** An instance of this structure is allocated for each VFS created. The |
| 39 | ** sqlite3_vfs.pAppData field of the VFS structure registered with SQLite |
| 40 | ** is set to point to it. |
| 41 | */ |
| 42 | struct Testvfs { |
| 43 | char *zName; /* Name of this VFS */ |
| 44 | sqlite3_vfs *pParent; /* The VFS to use for file IO */ |
| 45 | sqlite3_vfs *pVfs; /* The testvfs registered with SQLite */ |
| 46 | Tcl_Interp *interp; /* Interpreter to run script in */ |
| 47 | int nScript; /* Number of elements in array apScript */ |
| 48 | Tcl_Obj **apScript; /* Script to execute */ |
| 49 | TestvfsBuffer *pBuffer; /* List of shared buffers */ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 50 | int isNoshm; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 51 | }; |
| 52 | |
| 53 | /* |
| 54 | ** A shared-memory buffer. |
| 55 | */ |
| 56 | struct TestvfsBuffer { |
| 57 | char *zFile; /* Associated file name */ |
| 58 | int n; /* Size of allocated buffer in bytes */ |
| 59 | u8 *a; /* Buffer allocated using ckalloc() */ |
| 60 | int nRef; /* Number of references to this object */ |
| 61 | TestvfsBuffer *pNext; /* Next in linked list of all buffers */ |
| 62 | }; |
| 63 | |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 64 | |
| 65 | #define PARENTVFS(x) (((Testvfs *)((x)->pAppData))->pParent) |
| 66 | |
| 67 | |
| 68 | /* |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 69 | ** Method declarations for TestvfsFile. |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 70 | */ |
| 71 | static int tvfsClose(sqlite3_file*); |
| 72 | static int tvfsRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); |
| 73 | static int tvfsWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); |
| 74 | static int tvfsTruncate(sqlite3_file*, sqlite3_int64 size); |
| 75 | static int tvfsSync(sqlite3_file*, int flags); |
| 76 | static int tvfsFileSize(sqlite3_file*, sqlite3_int64 *pSize); |
| 77 | static int tvfsLock(sqlite3_file*, int); |
| 78 | static int tvfsUnlock(sqlite3_file*, int); |
| 79 | static int tvfsCheckReservedLock(sqlite3_file*, int *); |
| 80 | static int tvfsFileControl(sqlite3_file*, int op, void *pArg); |
| 81 | static int tvfsSectorSize(sqlite3_file*); |
| 82 | static int tvfsDeviceCharacteristics(sqlite3_file*); |
| 83 | |
| 84 | /* |
| 85 | ** Method declarations for tvfs_vfs. |
| 86 | */ |
| 87 | static int tvfsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); |
| 88 | static int tvfsDelete(sqlite3_vfs*, const char *zName, int syncDir); |
| 89 | static int tvfsAccess(sqlite3_vfs*, const char *zName, int flags, int *); |
| 90 | static int tvfsFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); |
| 91 | #ifndef SQLITE_OMIT_LOAD_EXTENSION |
| 92 | static void *tvfsDlOpen(sqlite3_vfs*, const char *zFilename); |
| 93 | static void tvfsDlError(sqlite3_vfs*, int nByte, char *zErrMsg); |
| 94 | static void (*tvfsDlSym(sqlite3_vfs*,void*, const char *zSymbol))(void); |
| 95 | static void tvfsDlClose(sqlite3_vfs*, void*); |
| 96 | #endif /* SQLITE_OMIT_LOAD_EXTENSION */ |
| 97 | static int tvfsRandomness(sqlite3_vfs*, int nByte, char *zOut); |
| 98 | static int tvfsSleep(sqlite3_vfs*, int microseconds); |
| 99 | static int tvfsCurrentTime(sqlite3_vfs*, double*); |
| 100 | |
drh | d9e5c4f | 2010-05-12 18:01:39 +0000 | [diff] [blame] | 101 | static int tvfsShmOpen(sqlite3_file*); |
| 102 | static int tvfsShmSize(sqlite3_file*, int , int *); |
drh | 5939f44 | 2010-05-18 13:27:12 +0000 | [diff] [blame] | 103 | static int tvfsShmGet(sqlite3_file*, int , int *, volatile void **); |
drh | d9e5c4f | 2010-05-12 18:01:39 +0000 | [diff] [blame] | 104 | static int tvfsShmRelease(sqlite3_file*); |
drh | 73b64e4 | 2010-05-30 19:55:15 +0000 | [diff] [blame^] | 105 | static int tvfsShmLock(sqlite3_file*, int , int, int); |
drh | 286a288 | 2010-05-20 23:51:06 +0000 | [diff] [blame] | 106 | static void tvfsShmBarrier(sqlite3_file*); |
drh | d9e5c4f | 2010-05-12 18:01:39 +0000 | [diff] [blame] | 107 | static int tvfsShmClose(sqlite3_file*, int); |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 108 | |
| 109 | static sqlite3_io_methods tvfs_io_methods = { |
drh | d9e5c4f | 2010-05-12 18:01:39 +0000 | [diff] [blame] | 110 | 2, /* iVersion */ |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 111 | tvfsClose, /* xClose */ |
| 112 | tvfsRead, /* xRead */ |
| 113 | tvfsWrite, /* xWrite */ |
| 114 | tvfsTruncate, /* xTruncate */ |
| 115 | tvfsSync, /* xSync */ |
| 116 | tvfsFileSize, /* xFileSize */ |
| 117 | tvfsLock, /* xLock */ |
| 118 | tvfsUnlock, /* xUnlock */ |
| 119 | tvfsCheckReservedLock, /* xCheckReservedLock */ |
| 120 | tvfsFileControl, /* xFileControl */ |
| 121 | tvfsSectorSize, /* xSectorSize */ |
drh | d9e5c4f | 2010-05-12 18:01:39 +0000 | [diff] [blame] | 122 | tvfsDeviceCharacteristics, /* xDeviceCharacteristics */ |
| 123 | tvfsShmOpen, /* xShmOpen */ |
| 124 | tvfsShmSize, /* xShmSize */ |
| 125 | tvfsShmGet, /* xShmGet */ |
| 126 | tvfsShmRelease, /* xShmRelease */ |
| 127 | tvfsShmLock, /* xShmLock */ |
drh | 286a288 | 2010-05-20 23:51:06 +0000 | [diff] [blame] | 128 | tvfsShmBarrier, /* xShmBarrier */ |
drh | d9e5c4f | 2010-05-12 18:01:39 +0000 | [diff] [blame] | 129 | tvfsShmClose /* xShmClose */ |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 130 | }; |
| 131 | |
| 132 | /* |
| 133 | ** Close an tvfs-file. |
| 134 | */ |
| 135 | static int tvfsClose(sqlite3_file *pFile){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 136 | TestvfsFile *p = (TestvfsFile *)pFile; |
| 137 | if( p->pShmId ){ |
| 138 | Tcl_DecrRefCount(p->pShmId); |
| 139 | p->pShmId = 0; |
| 140 | } |
| 141 | if( pFile->pMethods ){ |
| 142 | ckfree((char *)pFile->pMethods); |
| 143 | } |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 144 | return sqlite3OsClose(p->pReal); |
| 145 | } |
| 146 | |
| 147 | /* |
| 148 | ** Read data from an tvfs-file. |
| 149 | */ |
| 150 | static int tvfsRead( |
| 151 | sqlite3_file *pFile, |
| 152 | void *zBuf, |
| 153 | int iAmt, |
| 154 | sqlite_int64 iOfst |
| 155 | ){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 156 | TestvfsFile *p = (TestvfsFile *)pFile; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 157 | return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst); |
| 158 | } |
| 159 | |
| 160 | /* |
| 161 | ** Write data to an tvfs-file. |
| 162 | */ |
| 163 | static int tvfsWrite( |
| 164 | sqlite3_file *pFile, |
| 165 | const void *zBuf, |
| 166 | int iAmt, |
| 167 | sqlite_int64 iOfst |
| 168 | ){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 169 | TestvfsFile *p = (TestvfsFile *)pFile; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 170 | return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst); |
| 171 | } |
| 172 | |
| 173 | /* |
| 174 | ** Truncate an tvfs-file. |
| 175 | */ |
| 176 | static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 177 | TestvfsFile *p = (TestvfsFile *)pFile; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 178 | return sqlite3OsTruncate(p->pReal, size); |
| 179 | } |
| 180 | |
| 181 | /* |
| 182 | ** Sync an tvfs-file. |
| 183 | */ |
| 184 | static int tvfsSync(sqlite3_file *pFile, int flags){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 185 | TestvfsFile *p = (TestvfsFile *)pFile; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 186 | return sqlite3OsSync(p->pReal, flags); |
| 187 | } |
| 188 | |
| 189 | /* |
| 190 | ** Return the current file-size of an tvfs-file. |
| 191 | */ |
| 192 | static int tvfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 193 | TestvfsFile *p = (TestvfsFile *)pFile; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 194 | return sqlite3OsFileSize(p->pReal, pSize); |
| 195 | } |
| 196 | |
| 197 | /* |
| 198 | ** Lock an tvfs-file. |
| 199 | */ |
| 200 | static int tvfsLock(sqlite3_file *pFile, int eLock){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 201 | TestvfsFile *p = (TestvfsFile *)pFile; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 202 | return sqlite3OsLock(p->pReal, eLock); |
| 203 | } |
| 204 | |
| 205 | /* |
| 206 | ** Unlock an tvfs-file. |
| 207 | */ |
| 208 | static int tvfsUnlock(sqlite3_file *pFile, int eLock){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 209 | TestvfsFile *p = (TestvfsFile *)pFile; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 210 | return sqlite3OsUnlock(p->pReal, eLock); |
| 211 | } |
| 212 | |
| 213 | /* |
| 214 | ** Check if another file-handle holds a RESERVED lock on an tvfs-file. |
| 215 | */ |
| 216 | static int tvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 217 | TestvfsFile *p = (TestvfsFile *)pFile; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 218 | return sqlite3OsCheckReservedLock(p->pReal, pResOut); |
| 219 | } |
| 220 | |
| 221 | /* |
| 222 | ** File control method. For custom operations on an tvfs-file. |
| 223 | */ |
| 224 | static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 225 | TestvfsFile *p = (TestvfsFile *)pFile; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 226 | return sqlite3OsFileControl(p->pReal, op, pArg); |
| 227 | } |
| 228 | |
| 229 | /* |
| 230 | ** Return the sector-size in bytes for an tvfs-file. |
| 231 | */ |
| 232 | static int tvfsSectorSize(sqlite3_file *pFile){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 233 | TestvfsFile *p = (TestvfsFile *)pFile; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 234 | return sqlite3OsSectorSize(p->pReal); |
| 235 | } |
| 236 | |
| 237 | /* |
| 238 | ** Return the device characteristic flags supported by an tvfs-file. |
| 239 | */ |
| 240 | static int tvfsDeviceCharacteristics(sqlite3_file *pFile){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 241 | TestvfsFile *p = (TestvfsFile *)pFile; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 242 | return sqlite3OsDeviceCharacteristics(p->pReal); |
| 243 | } |
| 244 | |
| 245 | /* |
| 246 | ** Open an tvfs file handle. |
| 247 | */ |
| 248 | static int tvfsOpen( |
| 249 | sqlite3_vfs *pVfs, |
| 250 | const char *zName, |
| 251 | sqlite3_file *pFile, |
| 252 | int flags, |
| 253 | int *pOutFlags |
| 254 | ){ |
| 255 | int rc; |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 256 | TestvfsFile *p = (TestvfsFile *)pFile; |
drh | d9e5c4f | 2010-05-12 18:01:39 +0000 | [diff] [blame] | 257 | p->pShm = 0; |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 258 | p->pShmId = 0; |
drh | d9e5c4f | 2010-05-12 18:01:39 +0000 | [diff] [blame] | 259 | p->zFilename = zName; |
| 260 | p->pVfs = pVfs; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 261 | p->pReal = (sqlite3_file *)&p[1]; |
| 262 | rc = sqlite3OsOpen(PARENTVFS(pVfs), zName, p->pReal, flags, pOutFlags); |
| 263 | if( p->pReal->pMethods ){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 264 | sqlite3_io_methods *pMethods; |
| 265 | pMethods = (sqlite3_io_methods *)ckalloc(sizeof(sqlite3_io_methods)); |
| 266 | memcpy(pMethods, &tvfs_io_methods, sizeof(sqlite3_io_methods)); |
| 267 | if( ((Testvfs *)pVfs->pAppData)->isNoshm ){ |
| 268 | pMethods->xShmOpen = 0; |
| 269 | pMethods->xShmGet = 0; |
| 270 | pMethods->xShmSize = 0; |
| 271 | pMethods->xShmRelease = 0; |
| 272 | pMethods->xShmClose = 0; |
| 273 | pMethods->xShmLock = 0; |
drh | 286a288 | 2010-05-20 23:51:06 +0000 | [diff] [blame] | 274 | pMethods->xShmBarrier = 0; |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 275 | } |
| 276 | pFile->pMethods = pMethods; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 277 | } |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 278 | |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 279 | return rc; |
| 280 | } |
| 281 | |
| 282 | /* |
| 283 | ** Delete the file located at zPath. If the dirSync argument is true, |
| 284 | ** ensure the file-system modifications are synced to disk before |
| 285 | ** returning. |
| 286 | */ |
| 287 | static int tvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ |
| 288 | return sqlite3OsDelete(PARENTVFS(pVfs), zPath, dirSync); |
| 289 | } |
| 290 | |
| 291 | /* |
| 292 | ** Test for access permissions. Return true if the requested permission |
| 293 | ** is available, or false otherwise. |
| 294 | */ |
| 295 | static int tvfsAccess( |
| 296 | sqlite3_vfs *pVfs, |
| 297 | const char *zPath, |
| 298 | int flags, |
| 299 | int *pResOut |
| 300 | ){ |
| 301 | return sqlite3OsAccess(PARENTVFS(pVfs), zPath, flags, pResOut); |
| 302 | } |
| 303 | |
| 304 | /* |
| 305 | ** Populate buffer zOut with the full canonical pathname corresponding |
| 306 | ** to the pathname in zPath. zOut is guaranteed to point to a buffer |
| 307 | ** of at least (DEVSYM_MAX_PATHNAME+1) bytes. |
| 308 | */ |
| 309 | static int tvfsFullPathname( |
| 310 | sqlite3_vfs *pVfs, |
| 311 | const char *zPath, |
| 312 | int nOut, |
| 313 | char *zOut |
| 314 | ){ |
| 315 | return sqlite3OsFullPathname(PARENTVFS(pVfs), zPath, nOut, zOut); |
| 316 | } |
| 317 | |
| 318 | #ifndef SQLITE_OMIT_LOAD_EXTENSION |
| 319 | /* |
| 320 | ** Open the dynamic library located at zPath and return a handle. |
| 321 | */ |
| 322 | static void *tvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){ |
| 323 | return sqlite3OsDlOpen(PARENTVFS(pVfs), zPath); |
| 324 | } |
| 325 | |
| 326 | /* |
| 327 | ** Populate the buffer zErrMsg (size nByte bytes) with a human readable |
| 328 | ** utf-8 string describing the most recent error encountered associated |
| 329 | ** with dynamic libraries. |
| 330 | */ |
| 331 | static void tvfsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ |
| 332 | sqlite3OsDlError(PARENTVFS(pVfs), nByte, zErrMsg); |
| 333 | } |
| 334 | |
| 335 | /* |
| 336 | ** Return a pointer to the symbol zSymbol in the dynamic library pHandle. |
| 337 | */ |
| 338 | static void (*tvfsDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ |
| 339 | return sqlite3OsDlSym(PARENTVFS(pVfs), p, zSym); |
| 340 | } |
| 341 | |
| 342 | /* |
| 343 | ** Close the dynamic library handle pHandle. |
| 344 | */ |
| 345 | static void tvfsDlClose(sqlite3_vfs *pVfs, void *pHandle){ |
| 346 | sqlite3OsDlClose(PARENTVFS(pVfs), pHandle); |
| 347 | } |
| 348 | #endif /* SQLITE_OMIT_LOAD_EXTENSION */ |
| 349 | |
| 350 | /* |
| 351 | ** Populate the buffer pointed to by zBufOut with nByte bytes of |
| 352 | ** random data. |
| 353 | */ |
| 354 | static int tvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ |
| 355 | return sqlite3OsRandomness(PARENTVFS(pVfs), nByte, zBufOut); |
| 356 | } |
| 357 | |
| 358 | /* |
| 359 | ** Sleep for nMicro microseconds. Return the number of microseconds |
| 360 | ** actually slept. |
| 361 | */ |
| 362 | static int tvfsSleep(sqlite3_vfs *pVfs, int nMicro){ |
| 363 | return sqlite3OsSleep(PARENTVFS(pVfs), nMicro); |
| 364 | } |
| 365 | |
| 366 | /* |
| 367 | ** Return the current time as a Julian Day number in *pTimeOut. |
| 368 | */ |
| 369 | static int tvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ |
| 370 | return PARENTVFS(pVfs)->xCurrentTime(PARENTVFS(pVfs), pTimeOut); |
| 371 | } |
| 372 | |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 373 | static void tvfsGrowBuffer(TestvfsFile *pFd, int reqSize, int *pNewSize){ |
| 374 | TestvfsBuffer *pBuffer = pFd->pShm; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 375 | if( reqSize>pBuffer->n ){ |
| 376 | pBuffer->a = (u8 *)ckrealloc((char *)pBuffer->a, reqSize); |
dan | 8f6097c | 2010-05-06 07:43:58 +0000 | [diff] [blame] | 377 | memset(&pBuffer->a[pBuffer->n], 0x55, reqSize-pBuffer->n); |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 378 | pBuffer->n = reqSize; |
| 379 | } |
| 380 | *pNewSize = pBuffer->n; |
| 381 | } |
| 382 | |
| 383 | static void tvfsExecTcl( |
| 384 | Testvfs *p, |
| 385 | const char *zMethod, |
| 386 | Tcl_Obj *arg1, |
| 387 | Tcl_Obj *arg2, |
| 388 | Tcl_Obj *arg3 |
| 389 | ){ |
| 390 | int rc; /* Return code from Tcl_EvalObj() */ |
| 391 | int nArg; /* Elements in eval'd list */ |
| 392 | |
| 393 | p->apScript[p->nScript] = Tcl_NewStringObj(zMethod, -1); |
| 394 | p->apScript[p->nScript+1] = arg1; |
| 395 | p->apScript[p->nScript+2] = arg2; |
| 396 | p->apScript[p->nScript+3] = arg3; |
| 397 | |
| 398 | for(nArg=p->nScript; p->apScript[nArg]; nArg++){ |
| 399 | Tcl_IncrRefCount(p->apScript[nArg]); |
| 400 | } |
| 401 | |
| 402 | rc = Tcl_EvalObjv(p->interp, nArg, p->apScript, TCL_EVAL_GLOBAL); |
| 403 | if( rc!=TCL_OK ){ |
| 404 | Tcl_BackgroundError(p->interp); |
| 405 | Tcl_ResetResult(p->interp); |
| 406 | } |
| 407 | |
| 408 | for(nArg=p->nScript; p->apScript[nArg]; nArg++){ |
| 409 | Tcl_DecrRefCount(p->apScript[nArg]); |
| 410 | p->apScript[nArg] = 0; |
| 411 | } |
| 412 | } |
| 413 | |
| 414 | static int tvfsResultCode(Testvfs *p, int *pRc){ |
| 415 | struct errcode { |
| 416 | int eCode; |
| 417 | const char *zCode; |
| 418 | } aCode[] = { |
| 419 | { SQLITE_OK, "SQLITE_OK" }, |
| 420 | { SQLITE_ERROR, "SQLITE_ERROR" }, |
| 421 | { SQLITE_IOERR, "SQLITE_IOERR" }, |
| 422 | { SQLITE_LOCKED, "SQLITE_LOCKED" }, |
dan | ff6dfc7 | 2010-05-06 12:15:48 +0000 | [diff] [blame] | 423 | { SQLITE_BUSY, "SQLITE_BUSY" }, |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 424 | }; |
| 425 | |
| 426 | const char *z; |
| 427 | int i; |
| 428 | |
| 429 | z = Tcl_GetStringResult(p->interp); |
| 430 | for(i=0; i<ArraySize(aCode); i++){ |
| 431 | if( 0==strcmp(z, aCode[i].zCode) ){ |
| 432 | *pRc = aCode[i].eCode; |
| 433 | return 1; |
| 434 | } |
| 435 | } |
| 436 | |
| 437 | return 0; |
| 438 | } |
| 439 | |
| 440 | static int tvfsShmOpen( |
drh | d9e5c4f | 2010-05-12 18:01:39 +0000 | [diff] [blame] | 441 | sqlite3_file *pFileDes |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 442 | ){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 443 | Testvfs *p; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 444 | int rc = SQLITE_OK; /* Return code */ |
| 445 | Tcl_Obj *pId = 0; /* Id for this connection */ |
| 446 | TestvfsBuffer *pBuffer; /* Buffer to open connection to */ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 447 | TestvfsFile *pFd; /* The testvfs file structure */ |
drh | d9e5c4f | 2010-05-12 18:01:39 +0000 | [diff] [blame] | 448 | |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 449 | pFd = (TestvfsFile*)pFileDes; |
| 450 | p = (Testvfs *)pFd->pVfs->pAppData; |
| 451 | assert( pFd->pShmId==0 && pFd->pShm==0 ); |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 452 | |
| 453 | /* Evaluate the Tcl script: |
| 454 | ** |
| 455 | ** SCRIPT xShmOpen FILENAME |
| 456 | ** |
| 457 | ** If the script returns an SQLite error code other than SQLITE_OK, an |
| 458 | ** error is returned to the caller. If it returns SQLITE_OK, the new |
| 459 | ** connection is named "anon". Otherwise, the value returned by the |
| 460 | ** script is used as the connection name. |
| 461 | */ |
drh | d9e5c4f | 2010-05-12 18:01:39 +0000 | [diff] [blame] | 462 | tvfsExecTcl(p, "xShmOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0); |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 463 | if( tvfsResultCode(p, &rc) ){ |
| 464 | if( rc!=SQLITE_OK ) return rc; |
| 465 | pId = Tcl_NewStringObj("anon", -1); |
| 466 | }else{ |
| 467 | pId = Tcl_GetObjResult(p->interp); |
| 468 | } |
| 469 | Tcl_IncrRefCount(pId); |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 470 | pFd->pShmId = pId; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 471 | |
| 472 | /* Search for a TestvfsBuffer. Create a new one if required. */ |
| 473 | for(pBuffer=p->pBuffer; pBuffer; pBuffer=pBuffer->pNext){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 474 | if( 0==strcmp(pFd->zFilename, pBuffer->zFile) ) break; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 475 | } |
| 476 | if( !pBuffer ){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 477 | int nByte = sizeof(TestvfsBuffer) + strlen(pFd->zFilename) + 1; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 478 | pBuffer = (TestvfsBuffer *)ckalloc(nByte); |
| 479 | memset(pBuffer, 0, nByte); |
| 480 | pBuffer->zFile = (char *)&pBuffer[1]; |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 481 | strcpy(pBuffer->zFile, pFd->zFilename); |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 482 | pBuffer->pNext = p->pBuffer; |
| 483 | p->pBuffer = pBuffer; |
| 484 | } |
| 485 | |
| 486 | /* Connect the TestvfsBuffer to the new TestvfsShm handle and return. */ |
| 487 | pBuffer->nRef++; |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 488 | pFd->pShm = pBuffer; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 489 | return SQLITE_OK; |
| 490 | } |
| 491 | |
| 492 | static int tvfsShmSize( |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 493 | sqlite3_file *pFile, |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 494 | int reqSize, |
| 495 | int *pNewSize |
| 496 | ){ |
| 497 | int rc = SQLITE_OK; |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 498 | TestvfsFile *pFd = (TestvfsFile *)pFile; |
| 499 | Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 500 | |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 501 | tvfsExecTcl(p, "xShmSize", |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 502 | Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0 |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 503 | ); |
| 504 | tvfsResultCode(p, &rc); |
dan | 8f6097c | 2010-05-06 07:43:58 +0000 | [diff] [blame] | 505 | if( rc==SQLITE_OK ){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 506 | tvfsGrowBuffer(pFd, reqSize, pNewSize); |
dan | 8f6097c | 2010-05-06 07:43:58 +0000 | [diff] [blame] | 507 | } |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 508 | return rc; |
| 509 | } |
| 510 | |
| 511 | static int tvfsShmGet( |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 512 | sqlite3_file *pFile, |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 513 | int reqMapSize, |
| 514 | int *pMapSize, |
drh | 5939f44 | 2010-05-18 13:27:12 +0000 | [diff] [blame] | 515 | volatile void **pp |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 516 | ){ |
| 517 | int rc = SQLITE_OK; |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 518 | TestvfsFile *pFd = (TestvfsFile *)pFile; |
| 519 | Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 520 | |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 521 | tvfsExecTcl(p, "xShmGet", |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 522 | Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0 |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 523 | ); |
| 524 | tvfsResultCode(p, &rc); |
dan | d41a29a | 2010-05-06 15:56:28 +0000 | [diff] [blame] | 525 | if( rc==SQLITE_OK ){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 526 | tvfsGrowBuffer(pFd, reqMapSize, pMapSize); |
| 527 | *pp = pFd->pShm->a; |
dan | d41a29a | 2010-05-06 15:56:28 +0000 | [diff] [blame] | 528 | } |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 529 | return rc; |
| 530 | } |
| 531 | |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 532 | static int tvfsShmRelease(sqlite3_file *pFile){ |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 533 | int rc = SQLITE_OK; |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 534 | TestvfsFile *pFd = (TestvfsFile *)pFile; |
| 535 | Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 536 | |
| 537 | tvfsExecTcl(p, "xShmRelease", |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 538 | Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0 |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 539 | ); |
| 540 | tvfsResultCode(p, &rc); |
| 541 | |
| 542 | return rc; |
| 543 | } |
| 544 | |
| 545 | static int tvfsShmLock( |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 546 | sqlite3_file *pFile, |
drh | 73b64e4 | 2010-05-30 19:55:15 +0000 | [diff] [blame^] | 547 | int ofst, |
| 548 | int n, |
| 549 | int flags |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 550 | ){ |
| 551 | int rc = SQLITE_OK; |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 552 | TestvfsFile *pFd = (TestvfsFile *)pFile; |
| 553 | Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); |
drh | 73b64e4 | 2010-05-30 19:55:15 +0000 | [diff] [blame^] | 554 | int nLock; |
| 555 | char zLock[80]; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 556 | |
drh | 73b64e4 | 2010-05-30 19:55:15 +0000 | [diff] [blame^] | 557 | sqlite3_snprintf(sizeof(zLock), zLock, "%d %d", ofst, n); |
| 558 | nLock = strlen(zLock); |
| 559 | if( flags & SQLITE_SHM_LOCK ){ |
| 560 | strcpy(&zLock[nLock], " lock"); |
| 561 | }else{ |
| 562 | strcpy(&zLock[nLock], " unlock"); |
| 563 | } |
| 564 | nLock += strlen(&zLock[nLock]); |
| 565 | if( flags & SQLITE_SHM_SHARED ){ |
| 566 | strcpy(&zLock[nLock], " shared"); |
| 567 | }else{ |
| 568 | strcpy(&zLock[nLock], " exclusive"); |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 569 | } |
| 570 | tvfsExecTcl(p, "xShmLock", |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 571 | Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 572 | Tcl_NewStringObj(zLock, -1) |
| 573 | ); |
| 574 | tvfsResultCode(p, &rc); |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 575 | return rc; |
| 576 | } |
| 577 | |
drh | 286a288 | 2010-05-20 23:51:06 +0000 | [diff] [blame] | 578 | static void tvfsShmBarrier(sqlite3_file *pFile){ |
| 579 | int rc = SQLITE_OK; |
| 580 | TestvfsFile *pFd = (TestvfsFile *)pFile; |
| 581 | Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); |
| 582 | |
| 583 | tvfsExecTcl(p, "xShmBarrier", |
| 584 | Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0 |
| 585 | ); |
| 586 | tvfsResultCode(p, &rc); |
| 587 | } |
| 588 | |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 589 | static int tvfsShmClose( |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 590 | sqlite3_file *pFile, |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 591 | int deleteFlag |
| 592 | ){ |
| 593 | int rc = SQLITE_OK; |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 594 | TestvfsFile *pFd = (TestvfsFile *)pFile; |
| 595 | Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); |
| 596 | TestvfsBuffer *pBuffer = pFd->pShm; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 597 | |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 598 | assert( pFd->pShmId && pFd->pShm ); |
dan | 8f6097c | 2010-05-06 07:43:58 +0000 | [diff] [blame] | 599 | #if 0 |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 600 | assert( (deleteFlag!=0)==(pBuffer->nRef==1) ); |
dan | 8f6097c | 2010-05-06 07:43:58 +0000 | [diff] [blame] | 601 | #endif |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 602 | |
| 603 | tvfsExecTcl(p, "xShmClose", |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 604 | Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0 |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 605 | ); |
| 606 | tvfsResultCode(p, &rc); |
| 607 | |
| 608 | pBuffer->nRef--; |
| 609 | if( pBuffer->nRef==0 ){ |
| 610 | TestvfsBuffer **pp; |
| 611 | for(pp=&p->pBuffer; *pp!=pBuffer; pp=&((*pp)->pNext)); |
| 612 | *pp = (*pp)->pNext; |
| 613 | ckfree((char *)pBuffer->a); |
| 614 | ckfree((char *)pBuffer); |
| 615 | } |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 616 | Tcl_DecrRefCount(pFd->pShmId); |
| 617 | pFd->pShmId = 0; |
| 618 | pFd->pShm = 0; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 619 | |
| 620 | return rc; |
| 621 | } |
| 622 | |
| 623 | static int testvfs_obj_cmd( |
| 624 | ClientData cd, |
| 625 | Tcl_Interp *interp, |
| 626 | int objc, |
| 627 | Tcl_Obj *CONST objv[] |
| 628 | ){ |
| 629 | Testvfs *p = (Testvfs *)cd; |
| 630 | |
| 631 | static const char *CMD_strs[] = { "shm", "delete", 0 }; |
| 632 | enum DB_enum { CMD_SHM, CMD_DELETE }; |
| 633 | int i; |
| 634 | |
| 635 | if( objc<2 ){ |
| 636 | Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); |
| 637 | return TCL_ERROR; |
| 638 | } |
| 639 | if( Tcl_GetIndexFromObj(interp, objv[1], CMD_strs, "subcommand", 0, &i) ){ |
| 640 | return TCL_ERROR; |
| 641 | } |
| 642 | Tcl_ResetResult(interp); |
| 643 | |
| 644 | switch( (enum DB_enum)i ){ |
| 645 | case CMD_SHM: { |
| 646 | TestvfsBuffer *pBuffer; |
| 647 | char *zName; |
| 648 | if( objc!=3 && objc!=4 ){ |
| 649 | Tcl_WrongNumArgs(interp, 2, objv, "FILE ?VALUE?"); |
| 650 | return TCL_ERROR; |
| 651 | } |
| 652 | zName = Tcl_GetString(objv[2]); |
| 653 | for(pBuffer=p->pBuffer; pBuffer; pBuffer=pBuffer->pNext){ |
| 654 | if( 0==strcmp(pBuffer->zFile, zName) ) break; |
| 655 | } |
| 656 | if( !pBuffer ){ |
| 657 | Tcl_AppendResult(interp, "no such file: ", zName, 0); |
| 658 | return TCL_ERROR; |
| 659 | } |
| 660 | if( objc==4 ){ |
| 661 | int n; |
| 662 | u8 *a = Tcl_GetByteArrayFromObj(objv[3], &n); |
| 663 | pBuffer->a = (u8 *)ckrealloc((char *)pBuffer->a, n); |
| 664 | pBuffer->n = n; |
| 665 | memcpy(pBuffer->a, a, n); |
| 666 | } |
| 667 | Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pBuffer->a, pBuffer->n)); |
| 668 | break; |
| 669 | } |
| 670 | case CMD_DELETE: { |
| 671 | Tcl_DeleteCommand(interp, Tcl_GetString(objv[0])); |
| 672 | break; |
| 673 | } |
| 674 | } |
| 675 | |
| 676 | return TCL_OK; |
| 677 | } |
| 678 | |
| 679 | static void testvfs_obj_del(ClientData cd){ |
| 680 | int i; |
| 681 | Testvfs *p = (Testvfs *)cd; |
| 682 | for(i=0; i<p->nScript; i++){ |
| 683 | Tcl_DecrRefCount(p->apScript[i]); |
| 684 | } |
| 685 | sqlite3_vfs_unregister(p->pVfs); |
| 686 | ckfree((char *)p->pVfs); |
| 687 | ckfree((char *)p); |
| 688 | } |
| 689 | |
| 690 | #define TESTVFS_MAX_ARGS 12 |
| 691 | |
| 692 | /* |
dan | 576bc32 | 2010-05-06 18:04:50 +0000 | [diff] [blame] | 693 | ** Usage: testvfs ?-noshm? VFSNAME SCRIPT |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 694 | ** |
| 695 | ** This command creates two things when it is invoked: an SQLite VFS, and |
| 696 | ** a Tcl command. Both are named VFSNAME. The VFS is installed. It is not |
| 697 | ** installed as the default VFS. |
| 698 | ** |
| 699 | ** The VFS passes all file I/O calls through to the underlying VFS. |
| 700 | ** |
| 701 | ** Whenever one of the xShmSize, xShmGet or xShmRelease methods of the VFS |
| 702 | ** are invoked, the SCRIPT is executed as follows: |
| 703 | ** |
| 704 | ** SCRIPT xShmSize FILENAME ID |
| 705 | ** SCRIPT xShmGet FILENAME ID |
| 706 | ** SCRIPT xShmRelease FILENAME ID |
| 707 | ** |
| 708 | ** The value returned by the invocation of SCRIPT above is interpreted as |
| 709 | ** an SQLite error code and returned to SQLite. Either a symbolic |
| 710 | ** "SQLITE_OK" or numeric "0" value may be returned. |
| 711 | ** |
| 712 | ** The contents of the shared-memory buffer associated with a given file |
| 713 | ** may be read and set using the following command: |
| 714 | ** |
| 715 | ** VFSNAME shm FILENAME ?NEWVALUE? |
| 716 | ** |
| 717 | ** When the xShmLock method is invoked by SQLite, the following script is |
| 718 | ** run: |
| 719 | ** |
| 720 | ** SCRIPT xShmLock FILENAME ID LOCK |
| 721 | ** |
drh | 73b64e4 | 2010-05-30 19:55:15 +0000 | [diff] [blame^] | 722 | ** where LOCK is of the form "OFFSET NBYTE lock/unlock shared/exclusive" |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 723 | */ |
| 724 | static int testvfs_cmd( |
| 725 | ClientData cd, |
| 726 | Tcl_Interp *interp, |
| 727 | int objc, |
| 728 | Tcl_Obj *CONST objv[] |
| 729 | ){ |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 730 | static sqlite3_vfs tvfs_vfs = { |
| 731 | 2, /* iVersion */ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 732 | sizeof(TestvfsFile), /* szOsFile */ |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 733 | 0, /* mxPathname */ |
| 734 | 0, /* pNext */ |
| 735 | 0, /* zName */ |
| 736 | 0, /* pAppData */ |
| 737 | tvfsOpen, /* xOpen */ |
| 738 | tvfsDelete, /* xDelete */ |
| 739 | tvfsAccess, /* xAccess */ |
| 740 | tvfsFullPathname, /* xFullPathname */ |
| 741 | #ifndef SQLITE_OMIT_LOAD_EXTENSION |
| 742 | tvfsDlOpen, /* xDlOpen */ |
| 743 | tvfsDlError, /* xDlError */ |
| 744 | tvfsDlSym, /* xDlSym */ |
| 745 | tvfsDlClose, /* xDlClose */ |
| 746 | #else |
| 747 | 0, /* xDlOpen */ |
| 748 | 0, /* xDlError */ |
| 749 | 0, /* xDlSym */ |
| 750 | 0, /* xDlClose */ |
| 751 | #endif /* SQLITE_OMIT_LOAD_EXTENSION */ |
| 752 | tvfsRandomness, /* xRandomness */ |
| 753 | tvfsSleep, /* xSleep */ |
| 754 | tvfsCurrentTime, /* xCurrentTime */ |
| 755 | 0, /* xGetLastError */ |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 756 | 0, |
| 757 | 0, |
| 758 | }; |
| 759 | |
| 760 | Testvfs *p; /* New object */ |
| 761 | sqlite3_vfs *pVfs; /* New VFS */ |
| 762 | char *zVfs; |
| 763 | Tcl_Obj *pScript; |
| 764 | int nScript; /* Number of elements in list pScript */ |
| 765 | Tcl_Obj **apScript; /* Array of pScript elements */ |
| 766 | int nByte; /* Bytes of space to allocate at p */ |
| 767 | int i; /* Counter variable */ |
dan | 576bc32 | 2010-05-06 18:04:50 +0000 | [diff] [blame] | 768 | int isNoshm = 0; /* True if -noshm is passed */ |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 769 | |
dan | 576bc32 | 2010-05-06 18:04:50 +0000 | [diff] [blame] | 770 | if( objc<3 ) goto bad_args; |
| 771 | if( strcmp(Tcl_GetString(objv[1]), "-noshm")==0 ){ |
| 772 | isNoshm = 1; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 773 | } |
dan | 576bc32 | 2010-05-06 18:04:50 +0000 | [diff] [blame] | 774 | if( objc!=3+isNoshm ) goto bad_args; |
| 775 | zVfs = Tcl_GetString(objv[isNoshm+1]); |
| 776 | pScript = objv[isNoshm+2]; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 777 | |
| 778 | if( TCL_OK!=Tcl_ListObjGetElements(interp, pScript, &nScript, &apScript) ){ |
| 779 | return TCL_ERROR; |
| 780 | } |
| 781 | |
| 782 | nByte = sizeof(Testvfs) |
| 783 | + (nScript+TESTVFS_MAX_ARGS)*sizeof(Tcl_Obj *) |
| 784 | + strlen(zVfs)+1; |
| 785 | p = (Testvfs *)ckalloc(nByte); |
| 786 | memset(p, 0, nByte); |
| 787 | |
| 788 | p->pParent = sqlite3_vfs_find(0); |
| 789 | p->interp = interp; |
| 790 | p->nScript = nScript; |
| 791 | p->apScript = (Tcl_Obj **)&p[1]; |
| 792 | for(i=0; i<nScript; i++){ |
| 793 | p->apScript[i] = apScript[i]; |
| 794 | Tcl_IncrRefCount(p->apScript[i]); |
| 795 | } |
| 796 | p->zName = (char *)&p->apScript[nScript+TESTVFS_MAX_ARGS]; |
| 797 | strcpy(p->zName, zVfs); |
| 798 | |
| 799 | pVfs = (sqlite3_vfs *)ckalloc(sizeof(sqlite3_vfs)); |
| 800 | memcpy(pVfs, &tvfs_vfs, sizeof(sqlite3_vfs)); |
| 801 | pVfs->pAppData = (void *)p; |
| 802 | pVfs->zName = p->zName; |
| 803 | pVfs->mxPathname = p->pParent->mxPathname; |
| 804 | pVfs->szOsFile += p->pParent->szOsFile; |
dan | 8f6097c | 2010-05-06 07:43:58 +0000 | [diff] [blame] | 805 | p->pVfs = pVfs; |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 806 | p->isNoshm = isNoshm; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 807 | |
| 808 | Tcl_CreateObjCommand(interp, zVfs, testvfs_obj_cmd, p, testvfs_obj_del); |
| 809 | sqlite3_vfs_register(pVfs, 0); |
| 810 | |
| 811 | return TCL_OK; |
dan | 576bc32 | 2010-05-06 18:04:50 +0000 | [diff] [blame] | 812 | |
| 813 | bad_args: |
| 814 | Tcl_WrongNumArgs(interp, 1, objv, "?-noshm? VFSNAME SCRIPT"); |
| 815 | return TCL_ERROR; |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 816 | } |
| 817 | |
| 818 | int Sqlitetestvfs_Init(Tcl_Interp *interp){ |
dan | 7fd555a | 2010-05-13 06:19:37 +0000 | [diff] [blame] | 819 | Tcl_CreateObjCommand(interp, "testvfs", testvfs_cmd, 0, 0); |
dan | c7991bd | 2010-05-05 19:04:59 +0000 | [diff] [blame] | 820 | return TCL_OK; |
| 821 | } |
| 822 | |
| 823 | #endif |