os/persistentdata/persistentstorage/sqlite3api/TEST/SRC/test_onefile.c
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/persistentdata/persistentstorage/sqlite3api/TEST/SRC/test_onefile.c	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,822 @@
     1.4 +/*
     1.5 +** 2007 September 14
     1.6 +**
     1.7 +** The author disclaims copyright to this source code.  In place of
     1.8 +** a legal notice, here is a blessing:
     1.9 +**
    1.10 +**    May you do good and not evil.
    1.11 +**    May you find forgiveness for yourself and forgive others.
    1.12 +**    May you share freely, never taking more than you give.
    1.13 +**
    1.14 +*************************************************************************
    1.15 +**
    1.16 +** $Id: test_onefile.c,v 1.9 2008/06/26 10:54:12 danielk1977 Exp $
    1.17 +**
    1.18 +** OVERVIEW:
    1.19 +**
    1.20 +**   This file contains some example code demonstrating how the SQLite 
    1.21 +**   vfs feature can be used to have SQLite operate directly on an 
    1.22 +**   embedded media, without using an intermediate file system.
    1.23 +**
    1.24 +**   Because this is only a demo designed to run on a workstation, the
    1.25 +**   underlying media is simulated using a regular file-system file. The
    1.26 +**   size of the file is fixed when it is first created (default size 10 MB).
    1.27 +**   From SQLite's point of view, this space is used to store a single
    1.28 +**   database file and the journal file. 
    1.29 +**
    1.30 +**   Any statement journal created is stored in volatile memory obtained 
    1.31 +**   from sqlite3_malloc(). Any attempt to create a temporary database file 
    1.32 +**   will fail (SQLITE_IOERR). To prevent SQLite from attempting this,
    1.33 +**   it should be configured to store all temporary database files in 
    1.34 +**   main memory (see pragma "temp_store" or the SQLITE_TEMP_STORE compile 
    1.35 +**   time option).
    1.36 +**
    1.37 +** ASSUMPTIONS:
    1.38 +**
    1.39 +**   After it has been created, the blob file is accessed using the
    1.40 +**   following three functions only:
    1.41 +**
    1.42 +**       mediaRead();            - Read a 512 byte block from the file.
    1.43 +**       mediaWrite();           - Write a 512 byte block to the file.
    1.44 +**       mediaSync();            - Tell the media hardware to sync.
    1.45 +**
    1.46 +**   It is assumed that these can be easily implemented by any "real"
    1.47 +**   media vfs driver adapting this code.
    1.48 +**
    1.49 +** FILE FORMAT:
    1.50 +**
    1.51 +**   The basic principle is that the "database file" is stored at the
    1.52 +**   beginning of the 10 MB blob and grows in a forward direction. The 
    1.53 +**   "journal file" is stored at the end of the 10MB blob and grows
    1.54 +**   in the reverse direction. If, during a transaction, insufficient
    1.55 +**   space is available to expand either the journal or database file,
    1.56 +**   an SQLITE_FULL error is returned. The database file is never allowed
    1.57 +**   to consume more than 90% of the blob space. If SQLite tries to
    1.58 +**   create a file larger than this, SQLITE_FULL is returned.
    1.59 +**
    1.60 +**   No allowance is made for "wear-leveling", as is required by.
    1.61 +**   embedded devices in the absence of equivalent hardware features.
    1.62 +**
    1.63 +**   The first 512 block byte of the file is reserved for storing the
    1.64 +**   size of the "database file". It is updated as part of the sync()
    1.65 +**   operation. On startup, it can only be trusted if no journal file
    1.66 +**   exists. If a journal-file does exist, then it stores the real size
    1.67 +**   of the database region. The second and subsequent blocks store the 
    1.68 +**   actual database content.
    1.69 +**
    1.70 +**   The size of the "journal file" is not stored persistently in the 
    1.71 +**   file. When the system is running, the size of the journal file is
    1.72 +**   stored in volatile memory. When recovering from a crash, this vfs
    1.73 +**   reports a very large size for the journal file. The normal journal
    1.74 +**   header and checksum mechanisms serve to prevent SQLite from 
    1.75 +**   processing any data that lies past the logical end of the journal.
    1.76 +**
    1.77 +**   When SQLite calls OsDelete() to delete the journal file, the final
    1.78 +**   512 bytes of the blob (the area containing the first journal header)
    1.79 +**   are zeroed.
    1.80 +**
    1.81 +** LOCKING:
    1.82 +**
    1.83 +**   File locking is a no-op. Only one connection may be open at any one
    1.84 +**   time using this demo vfs.
    1.85 +*/
    1.86 +
    1.87 +#include "sqlite3.h"
    1.88 +#include <assert.h>
    1.89 +#include <string.h>
    1.90 +
    1.91 +/*
    1.92 +** Maximum pathname length supported by the fs backend.
    1.93 +*/
    1.94 +#define BLOCKSIZE 512
    1.95 +#define BLOBSIZE 10485760
    1.96 +
    1.97 +/*
    1.98 +** Name used to identify this VFS.
    1.99 +*/
   1.100 +#define FS_VFS_NAME "fs"
   1.101 +
   1.102 +typedef struct fs_real_file fs_real_file;
   1.103 +struct fs_real_file {
   1.104 +  sqlite3_file *pFile;
   1.105 +  const char *zName;
   1.106 +  int nDatabase;              /* Current size of database region */
   1.107 +  int nJournal;               /* Current size of journal region */
   1.108 +  int nBlob;                  /* Total size of allocated blob */
   1.109 +  int nRef;                   /* Number of pointers to this structure */
   1.110 +  fs_real_file *pNext;
   1.111 +  fs_real_file **ppThis;
   1.112 +};
   1.113 +
   1.114 +typedef struct fs_file fs_file;
   1.115 +struct fs_file {
   1.116 +  sqlite3_file base;
   1.117 +  int eType;
   1.118 +  fs_real_file *pReal;
   1.119 +};
   1.120 +
   1.121 +typedef struct tmp_file tmp_file;
   1.122 +struct tmp_file {
   1.123 +  sqlite3_file base;
   1.124 +  int nSize;
   1.125 +  int nAlloc;
   1.126 +  char *zAlloc;
   1.127 +};
   1.128 +
   1.129 +/* Values for fs_file.eType. */
   1.130 +#define DATABASE_FILE   1
   1.131 +#define JOURNAL_FILE    2
   1.132 +
   1.133 +/*
   1.134 +** Method declarations for fs_file.
   1.135 +*/
   1.136 +static int fsClose(sqlite3_file*);
   1.137 +static int fsRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
   1.138 +static int fsWrite(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst);
   1.139 +static int fsTruncate(sqlite3_file*, sqlite3_int64 size);
   1.140 +static int fsSync(sqlite3_file*, int flags);
   1.141 +static int fsFileSize(sqlite3_file*, sqlite3_int64 *pSize);
   1.142 +static int fsLock(sqlite3_file*, int);
   1.143 +static int fsUnlock(sqlite3_file*, int);
   1.144 +static int fsCheckReservedLock(sqlite3_file*, int *pResOut);
   1.145 +static int fsFileControl(sqlite3_file*, int op, void *pArg);
   1.146 +static int fsSectorSize(sqlite3_file*);
   1.147 +static int fsDeviceCharacteristics(sqlite3_file*);
   1.148 +
   1.149 +/*
   1.150 +** Method declarations for tmp_file.
   1.151 +*/
   1.152 +static int tmpClose(sqlite3_file*);
   1.153 +static int tmpRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
   1.154 +static int tmpWrite(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst);
   1.155 +static int tmpTruncate(sqlite3_file*, sqlite3_int64 size);
   1.156 +static int tmpSync(sqlite3_file*, int flags);
   1.157 +static int tmpFileSize(sqlite3_file*, sqlite3_int64 *pSize);
   1.158 +static int tmpLock(sqlite3_file*, int);
   1.159 +static int tmpUnlock(sqlite3_file*, int);
   1.160 +static int tmpCheckReservedLock(sqlite3_file*, int *pResOut);
   1.161 +static int tmpFileControl(sqlite3_file*, int op, void *pArg);
   1.162 +static int tmpSectorSize(sqlite3_file*);
   1.163 +static int tmpDeviceCharacteristics(sqlite3_file*);
   1.164 +
   1.165 +/*
   1.166 +** Method declarations for fs_vfs.
   1.167 +*/
   1.168 +static int fsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
   1.169 +static int fsDelete(sqlite3_vfs*, const char *zName, int syncDir);
   1.170 +static int fsAccess(sqlite3_vfs*, const char *zName, int flags, int *);
   1.171 +static int fsFullPathname(sqlite3_vfs*, const char *zName, int nOut,char *zOut);
   1.172 +static void *fsDlOpen(sqlite3_vfs*, const char *zFilename);
   1.173 +static void fsDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
   1.174 +static void *fsDlSym(sqlite3_vfs*,void*, const char *zSymbol);
   1.175 +static void fsDlClose(sqlite3_vfs*, void*);
   1.176 +static int fsRandomness(sqlite3_vfs*, int nByte, char *zOut);
   1.177 +static int fsSleep(sqlite3_vfs*, int microseconds);
   1.178 +static int fsCurrentTime(sqlite3_vfs*, double*);
   1.179 +
   1.180 +
   1.181 +typedef struct fs_vfs_t fs_vfs_t;
   1.182 +struct fs_vfs_t {
   1.183 +  sqlite3_vfs base;
   1.184 +  fs_real_file *pFileList;
   1.185 +  sqlite3_vfs *pParent;
   1.186 +};
   1.187 +
   1.188 +static fs_vfs_t fs_vfs = {
   1.189 +  {
   1.190 +    1,                                          /* iVersion */
   1.191 +    0,                                          /* szOsFile */
   1.192 +    0,                                          /* mxPathname */
   1.193 +    0,                                          /* pNext */
   1.194 +    FS_VFS_NAME,                                /* zName */
   1.195 +    0,                                          /* pAppData */
   1.196 +    fsOpen,                                     /* xOpen */
   1.197 +    fsDelete,                                   /* xDelete */
   1.198 +    fsAccess,                                   /* xAccess */
   1.199 +    fsFullPathname,                             /* xFullPathname */
   1.200 +    fsDlOpen,                                   /* xDlOpen */
   1.201 +    fsDlError,                                  /* xDlError */
   1.202 +    fsDlSym,                                    /* xDlSym */
   1.203 +    fsDlClose,                                  /* xDlClose */
   1.204 +    fsRandomness,                               /* xRandomness */
   1.205 +    fsSleep,                                    /* xSleep */
   1.206 +    fsCurrentTime                               /* xCurrentTime */
   1.207 +  }, 
   1.208 +  0,                                            /* pFileList */
   1.209 +  0                                             /* pParent */
   1.210 +};
   1.211 +
   1.212 +static sqlite3_io_methods fs_io_methods = {
   1.213 +  1,                            /* iVersion */
   1.214 +  fsClose,                      /* xClose */
   1.215 +  fsRead,                       /* xRead */
   1.216 +  fsWrite,                      /* xWrite */
   1.217 +  fsTruncate,                   /* xTruncate */
   1.218 +  fsSync,                       /* xSync */
   1.219 +  fsFileSize,                   /* xFileSize */
   1.220 +  fsLock,                       /* xLock */
   1.221 +  fsUnlock,                     /* xUnlock */
   1.222 +  fsCheckReservedLock,          /* xCheckReservedLock */
   1.223 +  fsFileControl,                /* xFileControl */
   1.224 +  fsSectorSize,                 /* xSectorSize */
   1.225 +  fsDeviceCharacteristics       /* xDeviceCharacteristics */
   1.226 +};
   1.227 +
   1.228 +
   1.229 +static sqlite3_io_methods tmp_io_methods = {
   1.230 +  1,                            /* iVersion */
   1.231 +  tmpClose,                     /* xClose */
   1.232 +  tmpRead,                      /* xRead */
   1.233 +  tmpWrite,                     /* xWrite */
   1.234 +  tmpTruncate,                  /* xTruncate */
   1.235 +  tmpSync,                      /* xSync */
   1.236 +  tmpFileSize,                  /* xFileSize */
   1.237 +  tmpLock,                      /* xLock */
   1.238 +  tmpUnlock,                    /* xUnlock */
   1.239 +  tmpCheckReservedLock,         /* xCheckReservedLock */
   1.240 +  tmpFileControl,               /* xFileControl */
   1.241 +  tmpSectorSize,                /* xSectorSize */
   1.242 +  tmpDeviceCharacteristics      /* xDeviceCharacteristics */
   1.243 +};
   1.244 +
   1.245 +/* Useful macros used in several places */
   1.246 +#define MIN(x,y) ((x)<(y)?(x):(y))
   1.247 +#define MAX(x,y) ((x)>(y)?(x):(y))
   1.248 +
   1.249 +
   1.250 +/*
   1.251 +** Close a tmp-file.
   1.252 +*/
   1.253 +static int tmpClose(sqlite3_file *pFile){
   1.254 +  tmp_file *pTmp = (tmp_file *)pFile;
   1.255 +  sqlite3_free(pTmp->zAlloc);
   1.256 +  return SQLITE_OK;
   1.257 +}
   1.258 +
   1.259 +/*
   1.260 +** Read data from a tmp-file.
   1.261 +*/
   1.262 +static int tmpRead(
   1.263 +  sqlite3_file *pFile, 
   1.264 +  void *zBuf, 
   1.265 +  int iAmt, 
   1.266 +  sqlite_int64 iOfst
   1.267 +){
   1.268 +  tmp_file *pTmp = (tmp_file *)pFile;
   1.269 +  if( (iAmt+iOfst)>pTmp->nSize ){
   1.270 +    return SQLITE_IOERR_SHORT_READ;
   1.271 +  }
   1.272 +  memcpy(zBuf, &pTmp->zAlloc[iOfst], iAmt);
   1.273 +  return SQLITE_OK;
   1.274 +}
   1.275 +
   1.276 +/*
   1.277 +** Write data to a tmp-file.
   1.278 +*/
   1.279 +static int tmpWrite(
   1.280 +  sqlite3_file *pFile, 
   1.281 +  const void *zBuf, 
   1.282 +  int iAmt, 
   1.283 +  sqlite_int64 iOfst
   1.284 +){
   1.285 +  tmp_file *pTmp = (tmp_file *)pFile;
   1.286 +  if( (iAmt+iOfst)>pTmp->nAlloc ){
   1.287 +    int nNew = 2*(iAmt+iOfst+pTmp->nAlloc);
   1.288 +    char *zNew = sqlite3_realloc(pTmp->zAlloc, nNew);
   1.289 +    if( !zNew ){
   1.290 +      return SQLITE_NOMEM;
   1.291 +    }
   1.292 +    pTmp->zAlloc = zNew;
   1.293 +    pTmp->nAlloc = nNew;
   1.294 +  }
   1.295 +  memcpy(&pTmp->zAlloc[iOfst], zBuf, iAmt);
   1.296 +  pTmp->nSize = MAX(pTmp->nSize, iOfst+iAmt);
   1.297 +  return SQLITE_OK;
   1.298 +}
   1.299 +
   1.300 +/*
   1.301 +** Truncate a tmp-file.
   1.302 +*/
   1.303 +static int tmpTruncate(sqlite3_file *pFile, sqlite_int64 size){
   1.304 +  tmp_file *pTmp = (tmp_file *)pFile;
   1.305 +  pTmp->nSize = MIN(pTmp->nSize, size);
   1.306 +  return SQLITE_OK;
   1.307 +}
   1.308 +
   1.309 +/*
   1.310 +** Sync a tmp-file.
   1.311 +*/
   1.312 +static int tmpSync(sqlite3_file *pFile, int flags){
   1.313 +  return SQLITE_OK;
   1.314 +}
   1.315 +
   1.316 +/*
   1.317 +** Return the current file-size of a tmp-file.
   1.318 +*/
   1.319 +static int tmpFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
   1.320 +  tmp_file *pTmp = (tmp_file *)pFile;
   1.321 +  *pSize = pTmp->nSize;
   1.322 +  return SQLITE_OK;
   1.323 +}
   1.324 +
   1.325 +/*
   1.326 +** Lock a tmp-file.
   1.327 +*/
   1.328 +static int tmpLock(sqlite3_file *pFile, int eLock){
   1.329 +  return SQLITE_OK;
   1.330 +}
   1.331 +
   1.332 +/*
   1.333 +** Unlock a tmp-file.
   1.334 +*/
   1.335 +static int tmpUnlock(sqlite3_file *pFile, int eLock){
   1.336 +  return SQLITE_OK;
   1.337 +}
   1.338 +
   1.339 +/*
   1.340 +** Check if another file-handle holds a RESERVED lock on a tmp-file.
   1.341 +*/
   1.342 +static int tmpCheckReservedLock(sqlite3_file *pFile, int *pResOut){
   1.343 +  *pResOut = 0;
   1.344 +  return SQLITE_OK;
   1.345 +}
   1.346 +
   1.347 +/*
   1.348 +** File control method. For custom operations on a tmp-file.
   1.349 +*/
   1.350 +static int tmpFileControl(sqlite3_file *pFile, int op, void *pArg){
   1.351 +  return SQLITE_OK;
   1.352 +}
   1.353 +
   1.354 +/*
   1.355 +** Return the sector-size in bytes for a tmp-file.
   1.356 +*/
   1.357 +static int tmpSectorSize(sqlite3_file *pFile){
   1.358 +  return 0;
   1.359 +}
   1.360 +
   1.361 +/*
   1.362 +** Return the device characteristic flags supported by a tmp-file.
   1.363 +*/
   1.364 +static int tmpDeviceCharacteristics(sqlite3_file *pFile){
   1.365 +  return 0;
   1.366 +}
   1.367 +
   1.368 +/*
   1.369 +** Close an fs-file.
   1.370 +*/
   1.371 +static int fsClose(sqlite3_file *pFile){
   1.372 +  int rc = SQLITE_OK;
   1.373 +  fs_file *p = (fs_file *)pFile;
   1.374 +  fs_real_file *pReal = p->pReal;
   1.375 +
   1.376 +  /* Decrement the real_file ref-count. */
   1.377 +  pReal->nRef--;
   1.378 +  assert(pReal->nRef>=0);
   1.379 +
   1.380 +  /* When the ref-count reaches 0, destroy the structure */
   1.381 +  if( pReal->nRef==0 ){
   1.382 +    *pReal->ppThis = pReal->pNext;
   1.383 +    if( pReal->pNext ){
   1.384 +      pReal->pNext->ppThis = pReal->ppThis;
   1.385 +    }
   1.386 +    rc = pReal->pFile->pMethods->xClose(pReal->pFile);
   1.387 +    sqlite3_free(pReal);
   1.388 +  }
   1.389 +
   1.390 +  return rc;
   1.391 +}
   1.392 +
   1.393 +/*
   1.394 +** Read data from an fs-file.
   1.395 +*/
   1.396 +static int fsRead(
   1.397 +  sqlite3_file *pFile, 
   1.398 +  void *zBuf, 
   1.399 +  int iAmt, 
   1.400 +  sqlite_int64 iOfst
   1.401 +){
   1.402 +  int rc = SQLITE_OK;
   1.403 +  fs_file *p = (fs_file *)pFile;
   1.404 +  fs_real_file *pReal = p->pReal;
   1.405 +  sqlite3_file *pF = pReal->pFile;
   1.406 +
   1.407 +  if( (p->eType==DATABASE_FILE && (iAmt+iOfst)>pReal->nDatabase)
   1.408 +   || (p->eType==JOURNAL_FILE && (iAmt+iOfst)>pReal->nJournal)
   1.409 +  ){
   1.410 +    rc = SQLITE_IOERR_SHORT_READ;
   1.411 +  }else if( p->eType==DATABASE_FILE ){
   1.412 +    rc = pF->pMethods->xRead(pF, zBuf, iAmt, iOfst+BLOCKSIZE);
   1.413 +  }else{
   1.414 +    /* Journal file. */
   1.415 +    int iRem = iAmt;
   1.416 +    int iBuf = 0;
   1.417 +    int ii = iOfst;
   1.418 +    while( iRem>0 && rc==SQLITE_OK ){
   1.419 +      int iRealOff = pReal->nBlob - BLOCKSIZE*((ii/BLOCKSIZE)+1) + ii%BLOCKSIZE;
   1.420 +      int iRealAmt = MIN(iRem, BLOCKSIZE - (iRealOff%BLOCKSIZE));
   1.421 +
   1.422 +      rc = pF->pMethods->xRead(pF, &((char *)zBuf)[iBuf], iRealAmt, iRealOff);
   1.423 +      ii += iRealAmt;
   1.424 +      iBuf += iRealAmt;
   1.425 +      iRem -= iRealAmt;
   1.426 +    }
   1.427 +  }
   1.428 +
   1.429 +  return rc;
   1.430 +}
   1.431 +
   1.432 +/*
   1.433 +** Write data to an fs-file.
   1.434 +*/
   1.435 +static int fsWrite(
   1.436 +  sqlite3_file *pFile, 
   1.437 +  const void *zBuf, 
   1.438 +  int iAmt, 
   1.439 +  sqlite_int64 iOfst
   1.440 +){
   1.441 +  int rc = SQLITE_OK;
   1.442 +  fs_file *p = (fs_file *)pFile;
   1.443 +  fs_real_file *pReal = p->pReal;
   1.444 +  sqlite3_file *pF = pReal->pFile;
   1.445 +
   1.446 +  if( p->eType==DATABASE_FILE ){
   1.447 +    if( (iAmt+iOfst+BLOCKSIZE)>(pReal->nBlob-pReal->nJournal) ){
   1.448 +      rc = SQLITE_FULL;
   1.449 +    }else{
   1.450 +      rc = pF->pMethods->xWrite(pF, zBuf, iAmt, iOfst+BLOCKSIZE);
   1.451 +      if( rc==SQLITE_OK ){
   1.452 +        pReal->nDatabase = MAX(pReal->nDatabase, iAmt+iOfst);
   1.453 +      }
   1.454 +    }
   1.455 +  }else{
   1.456 +    /* Journal file. */
   1.457 +    int iRem = iAmt;
   1.458 +    int iBuf = 0;
   1.459 +    int ii = iOfst;
   1.460 +    while( iRem>0 && rc==SQLITE_OK ){
   1.461 +      int iRealOff = pReal->nBlob - BLOCKSIZE*((ii/BLOCKSIZE)+1) + ii%BLOCKSIZE;
   1.462 +      int iRealAmt = MIN(iRem, BLOCKSIZE - (iRealOff%BLOCKSIZE));
   1.463 +
   1.464 +      if( iRealOff<(pReal->nDatabase+BLOCKSIZE) ){
   1.465 +        rc = SQLITE_FULL;
   1.466 +      }else{
   1.467 +        rc = pF->pMethods->xWrite(pF, &((char *)zBuf)[iBuf], iRealAmt,iRealOff);
   1.468 +        ii += iRealAmt;
   1.469 +        iBuf += iRealAmt;
   1.470 +        iRem -= iRealAmt;
   1.471 +      }
   1.472 +    }
   1.473 +    if( rc==SQLITE_OK ){
   1.474 +      pReal->nJournal = MAX(pReal->nJournal, iAmt+iOfst);
   1.475 +    }
   1.476 +  }
   1.477 +
   1.478 +  return rc;
   1.479 +}
   1.480 +
   1.481 +/*
   1.482 +** Truncate an fs-file.
   1.483 +*/
   1.484 +static int fsTruncate(sqlite3_file *pFile, sqlite_int64 size){
   1.485 +  fs_file *p = (fs_file *)pFile;
   1.486 +  fs_real_file *pReal = p->pReal;
   1.487 +  if( p->eType==DATABASE_FILE ){
   1.488 +    pReal->nDatabase = MIN(pReal->nDatabase, size);
   1.489 +  }else{
   1.490 +    pReal->nJournal = MIN(pReal->nJournal, size);
   1.491 +  }
   1.492 +  return SQLITE_OK;
   1.493 +}
   1.494 +
   1.495 +/*
   1.496 +** Sync an fs-file.
   1.497 +*/
   1.498 +static int fsSync(sqlite3_file *pFile, int flags){
   1.499 +  fs_file *p = (fs_file *)pFile;
   1.500 +  fs_real_file *pReal = p->pReal;
   1.501 +  sqlite3_file *pRealFile = pReal->pFile;
   1.502 +  int rc = SQLITE_OK;
   1.503 +
   1.504 +  if( p->eType==DATABASE_FILE ){
   1.505 +    unsigned char zSize[4];
   1.506 +    zSize[0] = (pReal->nDatabase&0xFF000000)>>24;
   1.507 +    zSize[1] = (pReal->nDatabase&0x00FF0000)>>16;
   1.508 +    zSize[2] = (pReal->nDatabase&0x0000FF00)>>8;
   1.509 +    zSize[3] = (pReal->nDatabase&0x000000FF);
   1.510 +    rc = pRealFile->pMethods->xWrite(pRealFile, zSize, 4, 0);
   1.511 +  }
   1.512 +  if( rc==SQLITE_OK ){
   1.513 +    rc = pRealFile->pMethods->xSync(pRealFile, flags&(~SQLITE_SYNC_DATAONLY));
   1.514 +  }
   1.515 +
   1.516 +  return rc;
   1.517 +}
   1.518 +
   1.519 +/*
   1.520 +** Return the current file-size of an fs-file.
   1.521 +*/
   1.522 +static int fsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
   1.523 +  fs_file *p = (fs_file *)pFile;
   1.524 +  fs_real_file *pReal = p->pReal;
   1.525 +  if( p->eType==DATABASE_FILE ){
   1.526 +    *pSize = pReal->nDatabase;
   1.527 +  }else{
   1.528 +    *pSize = pReal->nJournal;
   1.529 +  }
   1.530 +  return SQLITE_OK;
   1.531 +}
   1.532 +
   1.533 +/*
   1.534 +** Lock an fs-file.
   1.535 +*/
   1.536 +static int fsLock(sqlite3_file *pFile, int eLock){
   1.537 +  return SQLITE_OK;
   1.538 +}
   1.539 +
   1.540 +/*
   1.541 +** Unlock an fs-file.
   1.542 +*/
   1.543 +static int fsUnlock(sqlite3_file *pFile, int eLock){
   1.544 +  return SQLITE_OK;
   1.545 +}
   1.546 +
   1.547 +/*
   1.548 +** Check if another file-handle holds a RESERVED lock on an fs-file.
   1.549 +*/
   1.550 +static int fsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
   1.551 +  *pResOut = 0;
   1.552 +  return SQLITE_OK;
   1.553 +}
   1.554 +
   1.555 +/*
   1.556 +** File control method. For custom operations on an fs-file.
   1.557 +*/
   1.558 +static int fsFileControl(sqlite3_file *pFile, int op, void *pArg){
   1.559 +  return SQLITE_OK;
   1.560 +}
   1.561 +
   1.562 +/*
   1.563 +** Return the sector-size in bytes for an fs-file.
   1.564 +*/
   1.565 +static int fsSectorSize(sqlite3_file *pFile){
   1.566 +  return BLOCKSIZE;
   1.567 +}
   1.568 +
   1.569 +/*
   1.570 +** Return the device characteristic flags supported by an fs-file.
   1.571 +*/
   1.572 +static int fsDeviceCharacteristics(sqlite3_file *pFile){
   1.573 +  return 0;
   1.574 +}
   1.575 +
   1.576 +/*
   1.577 +** Open an fs file handle.
   1.578 +*/
   1.579 +static int fsOpen(
   1.580 +  sqlite3_vfs *pVfs,
   1.581 +  const char *zName,
   1.582 +  sqlite3_file *pFile,
   1.583 +  int flags,
   1.584 +  int *pOutFlags
   1.585 +){
   1.586 +  fs_vfs_t *pFsVfs = (fs_vfs_t *)pVfs;
   1.587 +  fs_file *p = (fs_file *)pFile;
   1.588 +  fs_real_file *pReal = 0;
   1.589 +  int eType;
   1.590 +  int nName;
   1.591 +  int rc = SQLITE_OK;
   1.592 +
   1.593 +  if( 0==(flags&(SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_MAIN_JOURNAL)) ){
   1.594 +    tmp_file *p = (tmp_file *)pFile;
   1.595 +    memset(p, 0, sizeof(*p));
   1.596 +    p->base.pMethods = &tmp_io_methods;
   1.597 +    return SQLITE_OK;
   1.598 +  }
   1.599 +
   1.600 +  eType = ((flags&(SQLITE_OPEN_MAIN_DB))?DATABASE_FILE:JOURNAL_FILE);
   1.601 +  p->base.pMethods = &fs_io_methods;
   1.602 +  p->eType = eType;
   1.603 +
   1.604 +  assert(strlen("-journal")==8);
   1.605 +  nName = strlen(zName)-((eType==JOURNAL_FILE)?8:0);
   1.606 +  pReal=pFsVfs->pFileList; 
   1.607 +  for(; pReal && strncmp(pReal->zName, zName, nName); pReal=pReal->pNext);
   1.608 +
   1.609 +  if( !pReal ){
   1.610 +    sqlite3_int64 size;
   1.611 +    sqlite3_file *pRealFile;
   1.612 +    sqlite3_vfs *pParent = pFsVfs->pParent;
   1.613 +    assert(eType==DATABASE_FILE);
   1.614 +
   1.615 +    pReal = (fs_real_file *)sqlite3_malloc(sizeof(*pReal)+pParent->szOsFile);
   1.616 +    if( !pReal ){
   1.617 +      rc = SQLITE_NOMEM;
   1.618 +      goto open_out;
   1.619 +    }
   1.620 +    memset(pReal, 0, sizeof(*pReal)+pParent->szOsFile);
   1.621 +    pReal->zName = zName;
   1.622 +    pReal->pFile = (sqlite3_file *)(&pReal[1]);
   1.623 +
   1.624 +    rc = pParent->xOpen(pParent, zName, pReal->pFile, flags, pOutFlags);
   1.625 +    if( rc!=SQLITE_OK ){
   1.626 +      goto open_out;
   1.627 +    }
   1.628 +    pRealFile = pReal->pFile;
   1.629 +
   1.630 +    rc = pRealFile->pMethods->xFileSize(pRealFile, &size);
   1.631 +    if( rc!=SQLITE_OK ){
   1.632 +      goto open_out;
   1.633 +    }
   1.634 +    if( size==0 ){
   1.635 +      rc = pRealFile->pMethods->xWrite(pRealFile, "\0", 1, BLOBSIZE-1);
   1.636 +      pReal->nBlob = BLOBSIZE;
   1.637 +    }else{
   1.638 +      unsigned char zS[4];
   1.639 +      pReal->nBlob = size;
   1.640 +      rc = pRealFile->pMethods->xRead(pRealFile, zS, 4, 0);
   1.641 +      pReal->nDatabase = (zS[0]<<24)+(zS[1]<<16)+(zS[2]<<8)+zS[3];
   1.642 +      if( rc==SQLITE_OK ){
   1.643 +        rc = pRealFile->pMethods->xRead(pRealFile, zS, 4, pReal->nBlob-4);
   1.644 +        if( zS[0] || zS[1] || zS[2] || zS[3] ){
   1.645 +          pReal->nJournal = pReal->nBlob;
   1.646 +        }
   1.647 +      }
   1.648 +    }
   1.649 +
   1.650 +    if( rc==SQLITE_OK ){
   1.651 +      pReal->pNext = pFsVfs->pFileList;
   1.652 +      if( pReal->pNext ){
   1.653 +        pReal->pNext->ppThis = &pReal->pNext;
   1.654 +      }
   1.655 +      pReal->ppThis = &pFsVfs->pFileList;
   1.656 +      pFsVfs->pFileList = pReal;
   1.657 +    }
   1.658 +  }
   1.659 +
   1.660 +open_out:
   1.661 +  if( pReal ){
   1.662 +    if( rc==SQLITE_OK ){
   1.663 +      p->pReal = pReal;
   1.664 +      pReal->nRef++;
   1.665 +    }else{
   1.666 +      if( pReal->pFile->pMethods ){
   1.667 +        pReal->pFile->pMethods->xClose(pReal->pFile);
   1.668 +      }
   1.669 +      sqlite3_free(pReal);
   1.670 +    }
   1.671 +  }
   1.672 +  return rc;
   1.673 +}
   1.674 +
   1.675 +/*
   1.676 +** Delete the file located at zPath. If the dirSync argument is true,
   1.677 +** ensure the file-system modifications are synced to disk before
   1.678 +** returning.
   1.679 +*/
   1.680 +static int fsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
   1.681 +  int rc = SQLITE_OK;
   1.682 +  fs_vfs_t *pFsVfs = (fs_vfs_t *)pVfs;
   1.683 +  fs_real_file *pReal;
   1.684 +  sqlite3_file *pF;
   1.685 +  int nName = strlen(zPath) - 8;
   1.686 +
   1.687 +  assert(strlen("-journal")==8);
   1.688 +  assert(strcmp("-journal", &zPath[nName])==0);
   1.689 +
   1.690 +  pReal = pFsVfs->pFileList; 
   1.691 +  for(; pReal && strncmp(pReal->zName, zPath, nName); pReal=pReal->pNext);
   1.692 +  if( pReal ){
   1.693 +    pF = pReal->pFile;
   1.694 +    rc = pF->pMethods->xWrite(pF, "\0\0\0\0", 4, pReal->nBlob-BLOCKSIZE);
   1.695 +    if( rc==SQLITE_OK ){
   1.696 +      pReal->nJournal = 0;
   1.697 +    }
   1.698 +  }
   1.699 +  return rc;
   1.700 +}
   1.701 +
   1.702 +/*
   1.703 +** Test for access permissions. Return true if the requested permission
   1.704 +** is available, or false otherwise.
   1.705 +*/
   1.706 +static int fsAccess(
   1.707 +  sqlite3_vfs *pVfs, 
   1.708 +  const char *zPath, 
   1.709 +  int flags, 
   1.710 +  int *pResOut
   1.711 +){
   1.712 +  fs_vfs_t *pFsVfs = (fs_vfs_t *)pVfs;
   1.713 +  fs_real_file *pReal;
   1.714 +  int isJournal = 0;
   1.715 +  int nName = strlen(zPath);
   1.716 +
   1.717 +  if( flags!=SQLITE_ACCESS_EXISTS ){
   1.718 +    sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
   1.719 +    return pParent->xAccess(pParent, zPath, flags, pResOut);
   1.720 +  }
   1.721 +
   1.722 +  assert(strlen("-journal")==8);
   1.723 +  if( nName>8 && strcmp("-journal", &zPath[nName-8])==0 ){
   1.724 +    nName -= 8;
   1.725 +    isJournal = 1;
   1.726 +  }
   1.727 +
   1.728 +  pReal = pFsVfs->pFileList; 
   1.729 +  for(; pReal && strncmp(pReal->zName, zPath, nName); pReal=pReal->pNext);
   1.730 +
   1.731 +  *pResOut = (pReal && (!isJournal || pReal->nJournal>0));
   1.732 +  return SQLITE_OK;
   1.733 +}
   1.734 +
   1.735 +/*
   1.736 +** Populate buffer zOut with the full canonical pathname corresponding
   1.737 +** to the pathname in zPath. zOut is guaranteed to point to a buffer
   1.738 +** of at least (FS_MAX_PATHNAME+1) bytes.
   1.739 +*/
   1.740 +static int fsFullPathname(
   1.741 +  sqlite3_vfs *pVfs,            /* Pointer to vfs object */
   1.742 +  const char *zPath,            /* Possibly relative input path */
   1.743 +  int nOut,                     /* Size of output buffer in bytes */
   1.744 +  char *zOut                    /* Output buffer */
   1.745 +){
   1.746 +  sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
   1.747 +  return pParent->xFullPathname(pParent, zPath, nOut, zOut);
   1.748 +}
   1.749 +
   1.750 +/*
   1.751 +** Open the dynamic library located at zPath and return a handle.
   1.752 +*/
   1.753 +static void *fsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
   1.754 +  sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
   1.755 +  return pParent->xDlOpen(pParent, zPath);
   1.756 +}
   1.757 +
   1.758 +/*
   1.759 +** Populate the buffer zErrMsg (size nByte bytes) with a human readable
   1.760 +** utf-8 string describing the most recent error encountered associated 
   1.761 +** with dynamic libraries.
   1.762 +*/
   1.763 +static void fsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
   1.764 +  sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
   1.765 +  pParent->xDlError(pParent, nByte, zErrMsg);
   1.766 +}
   1.767 +
   1.768 +/*
   1.769 +** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
   1.770 +*/
   1.771 +static void *fsDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){
   1.772 +  sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
   1.773 +  return pParent->xDlSym(pParent, pHandle, zSymbol);
   1.774 +}
   1.775 +
   1.776 +/*
   1.777 +** Close the dynamic library handle pHandle.
   1.778 +*/
   1.779 +static void fsDlClose(sqlite3_vfs *pVfs, void *pHandle){
   1.780 +  sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
   1.781 +  pParent->xDlClose(pParent, pHandle);
   1.782 +}
   1.783 +
   1.784 +/*
   1.785 +** Populate the buffer pointed to by zBufOut with nByte bytes of 
   1.786 +** random data.
   1.787 +*/
   1.788 +static int fsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
   1.789 +  sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
   1.790 +  return pParent->xRandomness(pParent, nByte, zBufOut);
   1.791 +}
   1.792 +
   1.793 +/*
   1.794 +** Sleep for nMicro microseconds. Return the number of microseconds 
   1.795 +** actually slept.
   1.796 +*/
   1.797 +static int fsSleep(sqlite3_vfs *pVfs, int nMicro){
   1.798 +  sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
   1.799 +  return pParent->xSleep(pParent, nMicro);
   1.800 +}
   1.801 +
   1.802 +/*
   1.803 +** Return the current time as a Julian Day number in *pTimeOut.
   1.804 +*/
   1.805 +static int fsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
   1.806 +  sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
   1.807 +  return pParent->xCurrentTime(pParent, pTimeOut);
   1.808 +}
   1.809 +
   1.810 +/*
   1.811 +** This procedure registers the fs vfs with SQLite. If the argument is
   1.812 +** true, the fs vfs becomes the new default vfs. It is the only publicly
   1.813 +** available function in this file.
   1.814 +*/
   1.815 +int fs_register(){
   1.816 +  if( fs_vfs.pParent ) return SQLITE_OK;
   1.817 +  fs_vfs.pParent = sqlite3_vfs_find(0);
   1.818 +  fs_vfs.base.mxPathname = fs_vfs.pParent->mxPathname;
   1.819 +  fs_vfs.base.szOsFile = MAX(sizeof(tmp_file), sizeof(fs_file));
   1.820 +  return sqlite3_vfs_register(&fs_vfs.base, 0);
   1.821 +}
   1.822 +
   1.823 +#ifdef SQLITE_TEST
   1.824 +  int SqlitetestOnefile_Init() {return fs_register();}
   1.825 +#endif