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