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>