Annotation of embedaddon/sqlite3/src/test_onefile.c, revision 1.1.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>