Annotation of embedaddon/sqlite3/src/test_onefile.c, revision 1.1
1.1 ! misho 1: /*
! 2: ** 2007 September 14
! 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: ** OVERVIEW:
! 14: **
! 15: ** This file contains some example code demonstrating how the SQLite
! 16: ** vfs feature can be used to have SQLite operate directly on an
! 17: ** embedded media, without using an intermediate file system.
! 18: **
! 19: ** Because this is only a demo designed to run on a workstation, the
! 20: ** underlying media is simulated using a regular file-system file. The
! 21: ** size of the file is fixed when it is first created (default size 10 MB).
! 22: ** From SQLite's point of view, this space is used to store a single
! 23: ** database file and the journal file.
! 24: **
! 25: ** Any statement journal created is stored in volatile memory obtained
! 26: ** from sqlite3_malloc(). Any attempt to create a temporary database file
! 27: ** will fail (SQLITE_IOERR). To prevent SQLite from attempting this,
! 28: ** it should be configured to store all temporary database files in
! 29: ** main memory (see pragma "temp_store" or the SQLITE_TEMP_STORE compile
! 30: ** time option).
! 31: **
! 32: ** ASSUMPTIONS:
! 33: **
! 34: ** After it has been created, the blob file is accessed using the
! 35: ** following three functions only:
! 36: **
! 37: ** mediaRead(); - Read a 512 byte block from the file.
! 38: ** mediaWrite(); - Write a 512 byte block to the file.
! 39: ** mediaSync(); - Tell the media hardware to sync.
! 40: **
! 41: ** It is assumed that these can be easily implemented by any "real"
! 42: ** media vfs driver adapting this code.
! 43: **
! 44: ** FILE FORMAT:
! 45: **
! 46: ** The basic principle is that the "database file" is stored at the
! 47: ** beginning of the 10 MB blob and grows in a forward direction. The
! 48: ** "journal file" is stored at the end of the 10MB blob and grows
! 49: ** in the reverse direction. If, during a transaction, insufficient
! 50: ** space is available to expand either the journal or database file,
! 51: ** an SQLITE_FULL error is returned. The database file is never allowed
! 52: ** to consume more than 90% of the blob space. If SQLite tries to
! 53: ** create a file larger than this, SQLITE_FULL is returned.
! 54: **
! 55: ** No allowance is made for "wear-leveling", as is required by.
! 56: ** embedded devices in the absence of equivalent hardware features.
! 57: **
! 58: ** The first 512 block byte of the file is reserved for storing the
! 59: ** size of the "database file". It is updated as part of the sync()
! 60: ** operation. On startup, it can only be trusted if no journal file
! 61: ** exists. If a journal-file does exist, then it stores the real size
! 62: ** of the database region. The second and subsequent blocks store the
! 63: ** actual database content.
! 64: **
! 65: ** The size of the "journal file" is not stored persistently in the
! 66: ** file. When the system is running, the size of the journal file is
! 67: ** stored in volatile memory. When recovering from a crash, this vfs
! 68: ** reports a very large size for the journal file. The normal journal
! 69: ** header and checksum mechanisms serve to prevent SQLite from
! 70: ** processing any data that lies past the logical end of the journal.
! 71: **
! 72: ** When SQLite calls OsDelete() to delete the journal file, the final
! 73: ** 512 bytes of the blob (the area containing the first journal header)
! 74: ** are zeroed.
! 75: **
! 76: ** LOCKING:
! 77: **
! 78: ** File locking is a no-op. Only one connection may be open at any one
! 79: ** time using this demo vfs.
! 80: */
! 81:
! 82: #include "sqlite3.h"
! 83: #include <assert.h>
! 84: #include <string.h>
! 85:
! 86: /*
! 87: ** Maximum pathname length supported by the fs backend.
! 88: */
! 89: #define BLOCKSIZE 512
! 90: #define BLOBSIZE 10485760
! 91:
! 92: /*
! 93: ** Name used to identify this VFS.
! 94: */
! 95: #define FS_VFS_NAME "fs"
! 96:
! 97: typedef struct fs_real_file fs_real_file;
! 98: struct fs_real_file {
! 99: sqlite3_file *pFile;
! 100: const char *zName;
! 101: int nDatabase; /* Current size of database region */
! 102: int nJournal; /* Current size of journal region */
! 103: int nBlob; /* Total size of allocated blob */
! 104: int nRef; /* Number of pointers to this structure */
! 105: fs_real_file *pNext;
! 106: fs_real_file **ppThis;
! 107: };
! 108:
! 109: typedef struct fs_file fs_file;
! 110: struct fs_file {
! 111: sqlite3_file base;
! 112: int eType;
! 113: fs_real_file *pReal;
! 114: };
! 115:
! 116: typedef struct tmp_file tmp_file;
! 117: struct tmp_file {
! 118: sqlite3_file base;
! 119: int nSize;
! 120: int nAlloc;
! 121: char *zAlloc;
! 122: };
! 123:
! 124: /* Values for fs_file.eType. */
! 125: #define DATABASE_FILE 1
! 126: #define JOURNAL_FILE 2
! 127:
! 128: /*
! 129: ** Method declarations for fs_file.
! 130: */
! 131: static int fsClose(sqlite3_file*);
! 132: static int fsRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
! 133: static int fsWrite(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst);
! 134: static int fsTruncate(sqlite3_file*, sqlite3_int64 size);
! 135: static int fsSync(sqlite3_file*, int flags);
! 136: static int fsFileSize(sqlite3_file*, sqlite3_int64 *pSize);
! 137: static int fsLock(sqlite3_file*, int);
! 138: static int fsUnlock(sqlite3_file*, int);
! 139: static int fsCheckReservedLock(sqlite3_file*, int *pResOut);
! 140: static int fsFileControl(sqlite3_file*, int op, void *pArg);
! 141: static int fsSectorSize(sqlite3_file*);
! 142: static int fsDeviceCharacteristics(sqlite3_file*);
! 143:
! 144: /*
! 145: ** Method declarations for tmp_file.
! 146: */
! 147: static int tmpClose(sqlite3_file*);
! 148: static int tmpRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
! 149: static int tmpWrite(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst);
! 150: static int tmpTruncate(sqlite3_file*, sqlite3_int64 size);
! 151: static int tmpSync(sqlite3_file*, int flags);
! 152: static int tmpFileSize(sqlite3_file*, sqlite3_int64 *pSize);
! 153: static int tmpLock(sqlite3_file*, int);
! 154: static int tmpUnlock(sqlite3_file*, int);
! 155: static int tmpCheckReservedLock(sqlite3_file*, int *pResOut);
! 156: static int tmpFileControl(sqlite3_file*, int op, void *pArg);
! 157: static int tmpSectorSize(sqlite3_file*);
! 158: static int tmpDeviceCharacteristics(sqlite3_file*);
! 159:
! 160: /*
! 161: ** Method declarations for fs_vfs.
! 162: */
! 163: static int fsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
! 164: static int fsDelete(sqlite3_vfs*, const char *zName, int syncDir);
! 165: static int fsAccess(sqlite3_vfs*, const char *zName, int flags, int *);
! 166: static int fsFullPathname(sqlite3_vfs*, const char *zName, int nOut,char *zOut);
! 167: static void *fsDlOpen(sqlite3_vfs*, const char *zFilename);
! 168: static void fsDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
! 169: static void (*fsDlSym(sqlite3_vfs*,void*, const char *zSymbol))(void);
! 170: static void fsDlClose(sqlite3_vfs*, void*);
! 171: static int fsRandomness(sqlite3_vfs*, int nByte, char *zOut);
! 172: static int fsSleep(sqlite3_vfs*, int microseconds);
! 173: static int fsCurrentTime(sqlite3_vfs*, double*);
! 174:
! 175:
! 176: typedef struct fs_vfs_t fs_vfs_t;
! 177: struct fs_vfs_t {
! 178: sqlite3_vfs base;
! 179: fs_real_file *pFileList;
! 180: sqlite3_vfs *pParent;
! 181: };
! 182:
! 183: static fs_vfs_t fs_vfs = {
! 184: {
! 185: 1, /* iVersion */
! 186: 0, /* szOsFile */
! 187: 0, /* mxPathname */
! 188: 0, /* pNext */
! 189: FS_VFS_NAME, /* zName */
! 190: 0, /* pAppData */
! 191: fsOpen, /* xOpen */
! 192: fsDelete, /* xDelete */
! 193: fsAccess, /* xAccess */
! 194: fsFullPathname, /* xFullPathname */
! 195: fsDlOpen, /* xDlOpen */
! 196: fsDlError, /* xDlError */
! 197: fsDlSym, /* xDlSym */
! 198: fsDlClose, /* xDlClose */
! 199: fsRandomness, /* xRandomness */
! 200: fsSleep, /* xSleep */
! 201: fsCurrentTime, /* xCurrentTime */
! 202: 0 /* xCurrentTimeInt64 */
! 203: },
! 204: 0, /* pFileList */
! 205: 0 /* pParent */
! 206: };
! 207:
! 208: static sqlite3_io_methods fs_io_methods = {
! 209: 1, /* iVersion */
! 210: fsClose, /* xClose */
! 211: fsRead, /* xRead */
! 212: fsWrite, /* xWrite */
! 213: fsTruncate, /* xTruncate */
! 214: fsSync, /* xSync */
! 215: fsFileSize, /* xFileSize */
! 216: fsLock, /* xLock */
! 217: fsUnlock, /* xUnlock */
! 218: fsCheckReservedLock, /* xCheckReservedLock */
! 219: fsFileControl, /* xFileControl */
! 220: fsSectorSize, /* xSectorSize */
! 221: fsDeviceCharacteristics, /* xDeviceCharacteristics */
! 222: 0, /* xShmMap */
! 223: 0, /* xShmLock */
! 224: 0, /* xShmBarrier */
! 225: 0 /* xShmUnmap */
! 226: };
! 227:
! 228:
! 229: static sqlite3_io_methods tmp_io_methods = {
! 230: 1, /* iVersion */
! 231: tmpClose, /* xClose */
! 232: tmpRead, /* xRead */
! 233: tmpWrite, /* xWrite */
! 234: tmpTruncate, /* xTruncate */
! 235: tmpSync, /* xSync */
! 236: tmpFileSize, /* xFileSize */
! 237: tmpLock, /* xLock */
! 238: tmpUnlock, /* xUnlock */
! 239: tmpCheckReservedLock, /* xCheckReservedLock */
! 240: tmpFileControl, /* xFileControl */
! 241: tmpSectorSize, /* xSectorSize */
! 242: tmpDeviceCharacteristics, /* xDeviceCharacteristics */
! 243: 0, /* xShmMap */
! 244: 0, /* xShmLock */
! 245: 0, /* xShmBarrier */
! 246: 0 /* xShmUnmap */
! 247: };
! 248:
! 249: /* Useful macros used in several places */
! 250: #define MIN(x,y) ((x)<(y)?(x):(y))
! 251: #define MAX(x,y) ((x)>(y)?(x):(y))
! 252:
! 253:
! 254: /*
! 255: ** Close a tmp-file.
! 256: */
! 257: static int tmpClose(sqlite3_file *pFile){
! 258: tmp_file *pTmp = (tmp_file *)pFile;
! 259: sqlite3_free(pTmp->zAlloc);
! 260: return SQLITE_OK;
! 261: }
! 262:
! 263: /*
! 264: ** Read data from a tmp-file.
! 265: */
! 266: static int tmpRead(
! 267: sqlite3_file *pFile,
! 268: void *zBuf,
! 269: int iAmt,
! 270: sqlite_int64 iOfst
! 271: ){
! 272: tmp_file *pTmp = (tmp_file *)pFile;
! 273: if( (iAmt+iOfst)>pTmp->nSize ){
! 274: return SQLITE_IOERR_SHORT_READ;
! 275: }
! 276: memcpy(zBuf, &pTmp->zAlloc[iOfst], iAmt);
! 277: return SQLITE_OK;
! 278: }
! 279:
! 280: /*
! 281: ** Write data to a tmp-file.
! 282: */
! 283: static int tmpWrite(
! 284: sqlite3_file *pFile,
! 285: const void *zBuf,
! 286: int iAmt,
! 287: sqlite_int64 iOfst
! 288: ){
! 289: tmp_file *pTmp = (tmp_file *)pFile;
! 290: if( (iAmt+iOfst)>pTmp->nAlloc ){
! 291: int nNew = 2*(iAmt+iOfst+pTmp->nAlloc);
! 292: char *zNew = sqlite3_realloc(pTmp->zAlloc, nNew);
! 293: if( !zNew ){
! 294: return SQLITE_NOMEM;
! 295: }
! 296: pTmp->zAlloc = zNew;
! 297: pTmp->nAlloc = nNew;
! 298: }
! 299: memcpy(&pTmp->zAlloc[iOfst], zBuf, iAmt);
! 300: pTmp->nSize = MAX(pTmp->nSize, iOfst+iAmt);
! 301: return SQLITE_OK;
! 302: }
! 303:
! 304: /*
! 305: ** Truncate a tmp-file.
! 306: */
! 307: static int tmpTruncate(sqlite3_file *pFile, sqlite_int64 size){
! 308: tmp_file *pTmp = (tmp_file *)pFile;
! 309: pTmp->nSize = MIN(pTmp->nSize, size);
! 310: return SQLITE_OK;
! 311: }
! 312:
! 313: /*
! 314: ** Sync a tmp-file.
! 315: */
! 316: static int tmpSync(sqlite3_file *pFile, int flags){
! 317: return SQLITE_OK;
! 318: }
! 319:
! 320: /*
! 321: ** Return the current file-size of a tmp-file.
! 322: */
! 323: static int tmpFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
! 324: tmp_file *pTmp = (tmp_file *)pFile;
! 325: *pSize = pTmp->nSize;
! 326: return SQLITE_OK;
! 327: }
! 328:
! 329: /*
! 330: ** Lock a tmp-file.
! 331: */
! 332: static int tmpLock(sqlite3_file *pFile, int eLock){
! 333: return SQLITE_OK;
! 334: }
! 335:
! 336: /*
! 337: ** Unlock a tmp-file.
! 338: */
! 339: static int tmpUnlock(sqlite3_file *pFile, int eLock){
! 340: return SQLITE_OK;
! 341: }
! 342:
! 343: /*
! 344: ** Check if another file-handle holds a RESERVED lock on a tmp-file.
! 345: */
! 346: static int tmpCheckReservedLock(sqlite3_file *pFile, int *pResOut){
! 347: *pResOut = 0;
! 348: return SQLITE_OK;
! 349: }
! 350:
! 351: /*
! 352: ** File control method. For custom operations on a tmp-file.
! 353: */
! 354: static int tmpFileControl(sqlite3_file *pFile, int op, void *pArg){
! 355: return SQLITE_OK;
! 356: }
! 357:
! 358: /*
! 359: ** Return the sector-size in bytes for a tmp-file.
! 360: */
! 361: static int tmpSectorSize(sqlite3_file *pFile){
! 362: return 0;
! 363: }
! 364:
! 365: /*
! 366: ** Return the device characteristic flags supported by a tmp-file.
! 367: */
! 368: static int tmpDeviceCharacteristics(sqlite3_file *pFile){
! 369: return 0;
! 370: }
! 371:
! 372: /*
! 373: ** Close an fs-file.
! 374: */
! 375: static int fsClose(sqlite3_file *pFile){
! 376: int rc = SQLITE_OK;
! 377: fs_file *p = (fs_file *)pFile;
! 378: fs_real_file *pReal = p->pReal;
! 379:
! 380: /* Decrement the real_file ref-count. */
! 381: pReal->nRef--;
! 382: assert(pReal->nRef>=0);
! 383:
! 384: /* When the ref-count reaches 0, destroy the structure */
! 385: if( pReal->nRef==0 ){
! 386: *pReal->ppThis = pReal->pNext;
! 387: if( pReal->pNext ){
! 388: pReal->pNext->ppThis = pReal->ppThis;
! 389: }
! 390: rc = pReal->pFile->pMethods->xClose(pReal->pFile);
! 391: sqlite3_free(pReal);
! 392: }
! 393:
! 394: return rc;
! 395: }
! 396:
! 397: /*
! 398: ** Read data from an fs-file.
! 399: */
! 400: static int fsRead(
! 401: sqlite3_file *pFile,
! 402: void *zBuf,
! 403: int iAmt,
! 404: sqlite_int64 iOfst
! 405: ){
! 406: int rc = SQLITE_OK;
! 407: fs_file *p = (fs_file *)pFile;
! 408: fs_real_file *pReal = p->pReal;
! 409: sqlite3_file *pF = pReal->pFile;
! 410:
! 411: if( (p->eType==DATABASE_FILE && (iAmt+iOfst)>pReal->nDatabase)
! 412: || (p->eType==JOURNAL_FILE && (iAmt+iOfst)>pReal->nJournal)
! 413: ){
! 414: rc = SQLITE_IOERR_SHORT_READ;
! 415: }else if( p->eType==DATABASE_FILE ){
! 416: rc = pF->pMethods->xRead(pF, zBuf, iAmt, iOfst+BLOCKSIZE);
! 417: }else{
! 418: /* Journal file. */
! 419: int iRem = iAmt;
! 420: int iBuf = 0;
! 421: int ii = iOfst;
! 422: while( iRem>0 && rc==SQLITE_OK ){
! 423: int iRealOff = pReal->nBlob - BLOCKSIZE*((ii/BLOCKSIZE)+1) + ii%BLOCKSIZE;
! 424: int iRealAmt = MIN(iRem, BLOCKSIZE - (iRealOff%BLOCKSIZE));
! 425:
! 426: rc = pF->pMethods->xRead(pF, &((char *)zBuf)[iBuf], iRealAmt, iRealOff);
! 427: ii += iRealAmt;
! 428: iBuf += iRealAmt;
! 429: iRem -= iRealAmt;
! 430: }
! 431: }
! 432:
! 433: return rc;
! 434: }
! 435:
! 436: /*
! 437: ** Write data to an fs-file.
! 438: */
! 439: static int fsWrite(
! 440: sqlite3_file *pFile,
! 441: const void *zBuf,
! 442: int iAmt,
! 443: sqlite_int64 iOfst
! 444: ){
! 445: int rc = SQLITE_OK;
! 446: fs_file *p = (fs_file *)pFile;
! 447: fs_real_file *pReal = p->pReal;
! 448: sqlite3_file *pF = pReal->pFile;
! 449:
! 450: if( p->eType==DATABASE_FILE ){
! 451: if( (iAmt+iOfst+BLOCKSIZE)>(pReal->nBlob-pReal->nJournal) ){
! 452: rc = SQLITE_FULL;
! 453: }else{
! 454: rc = pF->pMethods->xWrite(pF, zBuf, iAmt, iOfst+BLOCKSIZE);
! 455: if( rc==SQLITE_OK ){
! 456: pReal->nDatabase = MAX(pReal->nDatabase, iAmt+iOfst);
! 457: }
! 458: }
! 459: }else{
! 460: /* Journal file. */
! 461: int iRem = iAmt;
! 462: int iBuf = 0;
! 463: int ii = iOfst;
! 464: while( iRem>0 && rc==SQLITE_OK ){
! 465: int iRealOff = pReal->nBlob - BLOCKSIZE*((ii/BLOCKSIZE)+1) + ii%BLOCKSIZE;
! 466: int iRealAmt = MIN(iRem, BLOCKSIZE - (iRealOff%BLOCKSIZE));
! 467:
! 468: if( iRealOff<(pReal->nDatabase+BLOCKSIZE) ){
! 469: rc = SQLITE_FULL;
! 470: }else{
! 471: rc = pF->pMethods->xWrite(pF, &((char *)zBuf)[iBuf], iRealAmt,iRealOff);
! 472: ii += iRealAmt;
! 473: iBuf += iRealAmt;
! 474: iRem -= iRealAmt;
! 475: }
! 476: }
! 477: if( rc==SQLITE_OK ){
! 478: pReal->nJournal = MAX(pReal->nJournal, iAmt+iOfst);
! 479: }
! 480: }
! 481:
! 482: return rc;
! 483: }
! 484:
! 485: /*
! 486: ** Truncate an fs-file.
! 487: */
! 488: static int fsTruncate(sqlite3_file *pFile, sqlite_int64 size){
! 489: fs_file *p = (fs_file *)pFile;
! 490: fs_real_file *pReal = p->pReal;
! 491: if( p->eType==DATABASE_FILE ){
! 492: pReal->nDatabase = MIN(pReal->nDatabase, size);
! 493: }else{
! 494: pReal->nJournal = MIN(pReal->nJournal, size);
! 495: }
! 496: return SQLITE_OK;
! 497: }
! 498:
! 499: /*
! 500: ** Sync an fs-file.
! 501: */
! 502: static int fsSync(sqlite3_file *pFile, int flags){
! 503: fs_file *p = (fs_file *)pFile;
! 504: fs_real_file *pReal = p->pReal;
! 505: sqlite3_file *pRealFile = pReal->pFile;
! 506: int rc = SQLITE_OK;
! 507:
! 508: if( p->eType==DATABASE_FILE ){
! 509: unsigned char zSize[4];
! 510: zSize[0] = (pReal->nDatabase&0xFF000000)>>24;
! 511: zSize[1] = (pReal->nDatabase&0x00FF0000)>>16;
! 512: zSize[2] = (pReal->nDatabase&0x0000FF00)>>8;
! 513: zSize[3] = (pReal->nDatabase&0x000000FF);
! 514: rc = pRealFile->pMethods->xWrite(pRealFile, zSize, 4, 0);
! 515: }
! 516: if( rc==SQLITE_OK ){
! 517: rc = pRealFile->pMethods->xSync(pRealFile, flags&(~SQLITE_SYNC_DATAONLY));
! 518: }
! 519:
! 520: return rc;
! 521: }
! 522:
! 523: /*
! 524: ** Return the current file-size of an fs-file.
! 525: */
! 526: static int fsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
! 527: fs_file *p = (fs_file *)pFile;
! 528: fs_real_file *pReal = p->pReal;
! 529: if( p->eType==DATABASE_FILE ){
! 530: *pSize = pReal->nDatabase;
! 531: }else{
! 532: *pSize = pReal->nJournal;
! 533: }
! 534: return SQLITE_OK;
! 535: }
! 536:
! 537: /*
! 538: ** Lock an fs-file.
! 539: */
! 540: static int fsLock(sqlite3_file *pFile, int eLock){
! 541: return SQLITE_OK;
! 542: }
! 543:
! 544: /*
! 545: ** Unlock an fs-file.
! 546: */
! 547: static int fsUnlock(sqlite3_file *pFile, int eLock){
! 548: return SQLITE_OK;
! 549: }
! 550:
! 551: /*
! 552: ** Check if another file-handle holds a RESERVED lock on an fs-file.
! 553: */
! 554: static int fsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
! 555: *pResOut = 0;
! 556: return SQLITE_OK;
! 557: }
! 558:
! 559: /*
! 560: ** File control method. For custom operations on an fs-file.
! 561: */
! 562: static int fsFileControl(sqlite3_file *pFile, int op, void *pArg){
! 563: return SQLITE_OK;
! 564: }
! 565:
! 566: /*
! 567: ** Return the sector-size in bytes for an fs-file.
! 568: */
! 569: static int fsSectorSize(sqlite3_file *pFile){
! 570: return BLOCKSIZE;
! 571: }
! 572:
! 573: /*
! 574: ** Return the device characteristic flags supported by an fs-file.
! 575: */
! 576: static int fsDeviceCharacteristics(sqlite3_file *pFile){
! 577: return 0;
! 578: }
! 579:
! 580: /*
! 581: ** Open an fs file handle.
! 582: */
! 583: static int fsOpen(
! 584: sqlite3_vfs *pVfs,
! 585: const char *zName,
! 586: sqlite3_file *pFile,
! 587: int flags,
! 588: int *pOutFlags
! 589: ){
! 590: fs_vfs_t *pFsVfs = (fs_vfs_t *)pVfs;
! 591: fs_file *p = (fs_file *)pFile;
! 592: fs_real_file *pReal = 0;
! 593: int eType;
! 594: int nName;
! 595: int rc = SQLITE_OK;
! 596:
! 597: if( 0==(flags&(SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_MAIN_JOURNAL)) ){
! 598: tmp_file *p = (tmp_file *)pFile;
! 599: memset(p, 0, sizeof(*p));
! 600: p->base.pMethods = &tmp_io_methods;
! 601: return SQLITE_OK;
! 602: }
! 603:
! 604: eType = ((flags&(SQLITE_OPEN_MAIN_DB))?DATABASE_FILE:JOURNAL_FILE);
! 605: p->base.pMethods = &fs_io_methods;
! 606: p->eType = eType;
! 607:
! 608: assert(strlen("-journal")==8);
! 609: nName = strlen(zName)-((eType==JOURNAL_FILE)?8:0);
! 610: pReal=pFsVfs->pFileList;
! 611: for(; pReal && strncmp(pReal->zName, zName, nName); pReal=pReal->pNext);
! 612:
! 613: if( !pReal ){
! 614: int real_flags = (flags&~(SQLITE_OPEN_MAIN_DB))|SQLITE_OPEN_TEMP_DB;
! 615: sqlite3_int64 size;
! 616: sqlite3_file *pRealFile;
! 617: sqlite3_vfs *pParent = pFsVfs->pParent;
! 618: assert(eType==DATABASE_FILE);
! 619:
! 620: pReal = (fs_real_file *)sqlite3_malloc(sizeof(*pReal)+pParent->szOsFile);
! 621: if( !pReal ){
! 622: rc = SQLITE_NOMEM;
! 623: goto open_out;
! 624: }
! 625: memset(pReal, 0, sizeof(*pReal)+pParent->szOsFile);
! 626: pReal->zName = zName;
! 627: pReal->pFile = (sqlite3_file *)(&pReal[1]);
! 628:
! 629: rc = pParent->xOpen(pParent, zName, pReal->pFile, real_flags, pOutFlags);
! 630: if( rc!=SQLITE_OK ){
! 631: goto open_out;
! 632: }
! 633: pRealFile = pReal->pFile;
! 634:
! 635: rc = pRealFile->pMethods->xFileSize(pRealFile, &size);
! 636: if( rc!=SQLITE_OK ){
! 637: goto open_out;
! 638: }
! 639: if( size==0 ){
! 640: rc = pRealFile->pMethods->xWrite(pRealFile, "\0", 1, BLOBSIZE-1);
! 641: pReal->nBlob = BLOBSIZE;
! 642: }else{
! 643: unsigned char zS[4];
! 644: pReal->nBlob = size;
! 645: rc = pRealFile->pMethods->xRead(pRealFile, zS, 4, 0);
! 646: pReal->nDatabase = (zS[0]<<24)+(zS[1]<<16)+(zS[2]<<8)+zS[3];
! 647: if( rc==SQLITE_OK ){
! 648: rc = pRealFile->pMethods->xRead(pRealFile, zS, 4, pReal->nBlob-4);
! 649: if( zS[0] || zS[1] || zS[2] || zS[3] ){
! 650: pReal->nJournal = pReal->nBlob;
! 651: }
! 652: }
! 653: }
! 654:
! 655: if( rc==SQLITE_OK ){
! 656: pReal->pNext = pFsVfs->pFileList;
! 657: if( pReal->pNext ){
! 658: pReal->pNext->ppThis = &pReal->pNext;
! 659: }
! 660: pReal->ppThis = &pFsVfs->pFileList;
! 661: pFsVfs->pFileList = pReal;
! 662: }
! 663: }
! 664:
! 665: open_out:
! 666: if( pReal ){
! 667: if( rc==SQLITE_OK ){
! 668: p->pReal = pReal;
! 669: pReal->nRef++;
! 670: }else{
! 671: if( pReal->pFile->pMethods ){
! 672: pReal->pFile->pMethods->xClose(pReal->pFile);
! 673: }
! 674: sqlite3_free(pReal);
! 675: }
! 676: }
! 677: return rc;
! 678: }
! 679:
! 680: /*
! 681: ** Delete the file located at zPath. If the dirSync argument is true,
! 682: ** ensure the file-system modifications are synced to disk before
! 683: ** returning.
! 684: */
! 685: static int fsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
! 686: int rc = SQLITE_OK;
! 687: fs_vfs_t *pFsVfs = (fs_vfs_t *)pVfs;
! 688: fs_real_file *pReal;
! 689: sqlite3_file *pF;
! 690: int nName = strlen(zPath) - 8;
! 691:
! 692: assert(strlen("-journal")==8);
! 693: assert(strcmp("-journal", &zPath[nName])==0);
! 694:
! 695: pReal = pFsVfs->pFileList;
! 696: for(; pReal && strncmp(pReal->zName, zPath, nName); pReal=pReal->pNext);
! 697: if( pReal ){
! 698: pF = pReal->pFile;
! 699: rc = pF->pMethods->xWrite(pF, "\0\0\0\0", 4, pReal->nBlob-BLOCKSIZE);
! 700: if( rc==SQLITE_OK ){
! 701: pReal->nJournal = 0;
! 702: }
! 703: }
! 704: return rc;
! 705: }
! 706:
! 707: /*
! 708: ** Test for access permissions. Return true if the requested permission
! 709: ** is available, or false otherwise.
! 710: */
! 711: static int fsAccess(
! 712: sqlite3_vfs *pVfs,
! 713: const char *zPath,
! 714: int flags,
! 715: int *pResOut
! 716: ){
! 717: fs_vfs_t *pFsVfs = (fs_vfs_t *)pVfs;
! 718: fs_real_file *pReal;
! 719: int isJournal = 0;
! 720: int nName = strlen(zPath);
! 721:
! 722: if( flags!=SQLITE_ACCESS_EXISTS ){
! 723: sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
! 724: return pParent->xAccess(pParent, zPath, flags, pResOut);
! 725: }
! 726:
! 727: assert(strlen("-journal")==8);
! 728: if( nName>8 && strcmp("-journal", &zPath[nName-8])==0 ){
! 729: nName -= 8;
! 730: isJournal = 1;
! 731: }
! 732:
! 733: pReal = pFsVfs->pFileList;
! 734: for(; pReal && strncmp(pReal->zName, zPath, nName); pReal=pReal->pNext);
! 735:
! 736: *pResOut = (pReal && (!isJournal || pReal->nJournal>0));
! 737: return SQLITE_OK;
! 738: }
! 739:
! 740: /*
! 741: ** Populate buffer zOut with the full canonical pathname corresponding
! 742: ** to the pathname in zPath. zOut is guaranteed to point to a buffer
! 743: ** of at least (FS_MAX_PATHNAME+1) bytes.
! 744: */
! 745: static int fsFullPathname(
! 746: sqlite3_vfs *pVfs, /* Pointer to vfs object */
! 747: const char *zPath, /* Possibly relative input path */
! 748: int nOut, /* Size of output buffer in bytes */
! 749: char *zOut /* Output buffer */
! 750: ){
! 751: sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
! 752: return pParent->xFullPathname(pParent, zPath, nOut, zOut);
! 753: }
! 754:
! 755: /*
! 756: ** Open the dynamic library located at zPath and return a handle.
! 757: */
! 758: static void *fsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
! 759: sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
! 760: return pParent->xDlOpen(pParent, zPath);
! 761: }
! 762:
! 763: /*
! 764: ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
! 765: ** utf-8 string describing the most recent error encountered associated
! 766: ** with dynamic libraries.
! 767: */
! 768: static void fsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
! 769: sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
! 770: pParent->xDlError(pParent, nByte, zErrMsg);
! 771: }
! 772:
! 773: /*
! 774: ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
! 775: */
! 776: static void (*fsDlSym(sqlite3_vfs *pVfs, void *pH, const char *zSym))(void){
! 777: sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
! 778: return pParent->xDlSym(pParent, pH, zSym);
! 779: }
! 780:
! 781: /*
! 782: ** Close the dynamic library handle pHandle.
! 783: */
! 784: static void fsDlClose(sqlite3_vfs *pVfs, void *pHandle){
! 785: sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
! 786: pParent->xDlClose(pParent, pHandle);
! 787: }
! 788:
! 789: /*
! 790: ** Populate the buffer pointed to by zBufOut with nByte bytes of
! 791: ** random data.
! 792: */
! 793: static int fsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
! 794: sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
! 795: return pParent->xRandomness(pParent, nByte, zBufOut);
! 796: }
! 797:
! 798: /*
! 799: ** Sleep for nMicro microseconds. Return the number of microseconds
! 800: ** actually slept.
! 801: */
! 802: static int fsSleep(sqlite3_vfs *pVfs, int nMicro){
! 803: sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
! 804: return pParent->xSleep(pParent, nMicro);
! 805: }
! 806:
! 807: /*
! 808: ** Return the current time as a Julian Day number in *pTimeOut.
! 809: */
! 810: static int fsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
! 811: sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
! 812: return pParent->xCurrentTime(pParent, pTimeOut);
! 813: }
! 814:
! 815: /*
! 816: ** This procedure registers the fs vfs with SQLite. If the argument is
! 817: ** true, the fs vfs becomes the new default vfs. It is the only publicly
! 818: ** available function in this file.
! 819: */
! 820: int fs_register(void){
! 821: if( fs_vfs.pParent ) return SQLITE_OK;
! 822: fs_vfs.pParent = sqlite3_vfs_find(0);
! 823: fs_vfs.base.mxPathname = fs_vfs.pParent->mxPathname;
! 824: fs_vfs.base.szOsFile = MAX(sizeof(tmp_file), sizeof(fs_file));
! 825: return sqlite3_vfs_register(&fs_vfs.base, 0);
! 826: }
! 827:
! 828: #ifdef SQLITE_TEST
! 829: int SqlitetestOnefile_Init() {return fs_register();}
! 830: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>