| OLD | NEW | 
 | (Empty) | 
|    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.12 2009/04/07 11:21:29 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))(void); |  | 
|  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     int real_flags = (flags&~(SQLITE_OPEN_MAIN_DB))|SQLITE_OPEN_TEMP_DB; |  | 
|  608     sqlite3_int64 size; |  | 
|  609     sqlite3_file *pRealFile; |  | 
|  610     sqlite3_vfs *pParent = pFsVfs->pParent; |  | 
|  611     assert(eType==DATABASE_FILE); |  | 
|  612  |  | 
|  613     pReal = (fs_real_file *)sqlite3_malloc(sizeof(*pReal)+pParent->szOsFile); |  | 
|  614     if( !pReal ){ |  | 
|  615       rc = SQLITE_NOMEM; |  | 
|  616       goto open_out; |  | 
|  617     } |  | 
|  618     memset(pReal, 0, sizeof(*pReal)+pParent->szOsFile); |  | 
|  619     pReal->zName = zName; |  | 
|  620     pReal->pFile = (sqlite3_file *)(&pReal[1]); |  | 
|  621  |  | 
|  622     rc = pParent->xOpen(pParent, zName, pReal->pFile, real_flags, pOutFlags); |  | 
|  623     if( rc!=SQLITE_OK ){ |  | 
|  624       goto open_out; |  | 
|  625     } |  | 
|  626     pRealFile = pReal->pFile; |  | 
|  627  |  | 
|  628     rc = pRealFile->pMethods->xFileSize(pRealFile, &size); |  | 
|  629     if( rc!=SQLITE_OK ){ |  | 
|  630       goto open_out; |  | 
|  631     } |  | 
|  632     if( size==0 ){ |  | 
|  633       rc = pRealFile->pMethods->xWrite(pRealFile, "\0", 1, BLOBSIZE-1); |  | 
|  634       pReal->nBlob = BLOBSIZE; |  | 
|  635     }else{ |  | 
|  636       unsigned char zS[4]; |  | 
|  637       pReal->nBlob = size; |  | 
|  638       rc = pRealFile->pMethods->xRead(pRealFile, zS, 4, 0); |  | 
|  639       pReal->nDatabase = (zS[0]<<24)+(zS[1]<<16)+(zS[2]<<8)+zS[3]; |  | 
|  640       if( rc==SQLITE_OK ){ |  | 
|  641         rc = pRealFile->pMethods->xRead(pRealFile, zS, 4, pReal->nBlob-4); |  | 
|  642         if( zS[0] || zS[1] || zS[2] || zS[3] ){ |  | 
|  643           pReal->nJournal = pReal->nBlob; |  | 
|  644         } |  | 
|  645       } |  | 
|  646     } |  | 
|  647  |  | 
|  648     if( rc==SQLITE_OK ){ |  | 
|  649       pReal->pNext = pFsVfs->pFileList; |  | 
|  650       if( pReal->pNext ){ |  | 
|  651         pReal->pNext->ppThis = &pReal->pNext; |  | 
|  652       } |  | 
|  653       pReal->ppThis = &pFsVfs->pFileList; |  | 
|  654       pFsVfs->pFileList = pReal; |  | 
|  655     } |  | 
|  656   } |  | 
|  657  |  | 
|  658 open_out: |  | 
|  659   if( pReal ){ |  | 
|  660     if( rc==SQLITE_OK ){ |  | 
|  661       p->pReal = pReal; |  | 
|  662       pReal->nRef++; |  | 
|  663     }else{ |  | 
|  664       if( pReal->pFile->pMethods ){ |  | 
|  665         pReal->pFile->pMethods->xClose(pReal->pFile); |  | 
|  666       } |  | 
|  667       sqlite3_free(pReal); |  | 
|  668     } |  | 
|  669   } |  | 
|  670   return rc; |  | 
|  671 } |  | 
|  672  |  | 
|  673 /* |  | 
|  674 ** Delete the file located at zPath. If the dirSync argument is true, |  | 
|  675 ** ensure the file-system modifications are synced to disk before |  | 
|  676 ** returning. |  | 
|  677 */ |  | 
|  678 static int fsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ |  | 
|  679   int rc = SQLITE_OK; |  | 
|  680   fs_vfs_t *pFsVfs = (fs_vfs_t *)pVfs; |  | 
|  681   fs_real_file *pReal; |  | 
|  682   sqlite3_file *pF; |  | 
|  683   int nName = strlen(zPath) - 8; |  | 
|  684  |  | 
|  685   assert(strlen("-journal")==8); |  | 
|  686   assert(strcmp("-journal", &zPath[nName])==0); |  | 
|  687  |  | 
|  688   pReal = pFsVfs->pFileList;  |  | 
|  689   for(; pReal && strncmp(pReal->zName, zPath, nName); pReal=pReal->pNext); |  | 
|  690   if( pReal ){ |  | 
|  691     pF = pReal->pFile; |  | 
|  692     rc = pF->pMethods->xWrite(pF, "\0\0\0\0", 4, pReal->nBlob-BLOCKSIZE); |  | 
|  693     if( rc==SQLITE_OK ){ |  | 
|  694       pReal->nJournal = 0; |  | 
|  695     } |  | 
|  696   } |  | 
|  697   return rc; |  | 
|  698 } |  | 
|  699  |  | 
|  700 /* |  | 
|  701 ** Test for access permissions. Return true if the requested permission |  | 
|  702 ** is available, or false otherwise. |  | 
|  703 */ |  | 
|  704 static int fsAccess( |  | 
|  705   sqlite3_vfs *pVfs,  |  | 
|  706   const char *zPath,  |  | 
|  707   int flags,  |  | 
|  708   int *pResOut |  | 
|  709 ){ |  | 
|  710   fs_vfs_t *pFsVfs = (fs_vfs_t *)pVfs; |  | 
|  711   fs_real_file *pReal; |  | 
|  712   int isJournal = 0; |  | 
|  713   int nName = strlen(zPath); |  | 
|  714  |  | 
|  715   if( flags!=SQLITE_ACCESS_EXISTS ){ |  | 
|  716     sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; |  | 
|  717     return pParent->xAccess(pParent, zPath, flags, pResOut); |  | 
|  718   } |  | 
|  719  |  | 
|  720   assert(strlen("-journal")==8); |  | 
|  721   if( nName>8 && strcmp("-journal", &zPath[nName-8])==0 ){ |  | 
|  722     nName -= 8; |  | 
|  723     isJournal = 1; |  | 
|  724   } |  | 
|  725  |  | 
|  726   pReal = pFsVfs->pFileList;  |  | 
|  727   for(; pReal && strncmp(pReal->zName, zPath, nName); pReal=pReal->pNext); |  | 
|  728  |  | 
|  729   *pResOut = (pReal && (!isJournal || pReal->nJournal>0)); |  | 
|  730   return SQLITE_OK; |  | 
|  731 } |  | 
|  732  |  | 
|  733 /* |  | 
|  734 ** Populate buffer zOut with the full canonical pathname corresponding |  | 
|  735 ** to the pathname in zPath. zOut is guaranteed to point to a buffer |  | 
|  736 ** of at least (FS_MAX_PATHNAME+1) bytes. |  | 
|  737 */ |  | 
|  738 static int fsFullPathname( |  | 
|  739   sqlite3_vfs *pVfs,            /* Pointer to vfs object */ |  | 
|  740   const char *zPath,            /* Possibly relative input path */ |  | 
|  741   int nOut,                     /* Size of output buffer in bytes */ |  | 
|  742   char *zOut                    /* Output buffer */ |  | 
|  743 ){ |  | 
|  744   sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; |  | 
|  745   return pParent->xFullPathname(pParent, zPath, nOut, zOut); |  | 
|  746 } |  | 
|  747  |  | 
|  748 /* |  | 
|  749 ** Open the dynamic library located at zPath and return a handle. |  | 
|  750 */ |  | 
|  751 static void *fsDlOpen(sqlite3_vfs *pVfs, const char *zPath){ |  | 
|  752   sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; |  | 
|  753   return pParent->xDlOpen(pParent, zPath); |  | 
|  754 } |  | 
|  755  |  | 
|  756 /* |  | 
|  757 ** Populate the buffer zErrMsg (size nByte bytes) with a human readable |  | 
|  758 ** utf-8 string describing the most recent error encountered associated  |  | 
|  759 ** with dynamic libraries. |  | 
|  760 */ |  | 
|  761 static void fsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ |  | 
|  762   sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; |  | 
|  763   pParent->xDlError(pParent, nByte, zErrMsg); |  | 
|  764 } |  | 
|  765  |  | 
|  766 /* |  | 
|  767 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle. |  | 
|  768 */ |  | 
|  769 static void (*fsDlSym(sqlite3_vfs *pVfs, void *pH, const char *zSym))(void){ |  | 
|  770   sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; |  | 
|  771   return pParent->xDlSym(pParent, pH, zSym); |  | 
|  772 } |  | 
|  773  |  | 
|  774 /* |  | 
|  775 ** Close the dynamic library handle pHandle. |  | 
|  776 */ |  | 
|  777 static void fsDlClose(sqlite3_vfs *pVfs, void *pHandle){ |  | 
|  778   sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; |  | 
|  779   pParent->xDlClose(pParent, pHandle); |  | 
|  780 } |  | 
|  781  |  | 
|  782 /* |  | 
|  783 ** Populate the buffer pointed to by zBufOut with nByte bytes of  |  | 
|  784 ** random data. |  | 
|  785 */ |  | 
|  786 static int fsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ |  | 
|  787   sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; |  | 
|  788   return pParent->xRandomness(pParent, nByte, zBufOut); |  | 
|  789 } |  | 
|  790  |  | 
|  791 /* |  | 
|  792 ** Sleep for nMicro microseconds. Return the number of microseconds  |  | 
|  793 ** actually slept. |  | 
|  794 */ |  | 
|  795 static int fsSleep(sqlite3_vfs *pVfs, int nMicro){ |  | 
|  796   sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; |  | 
|  797   return pParent->xSleep(pParent, nMicro); |  | 
|  798 } |  | 
|  799  |  | 
|  800 /* |  | 
|  801 ** Return the current time as a Julian Day number in *pTimeOut. |  | 
|  802 */ |  | 
|  803 static int fsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ |  | 
|  804   sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; |  | 
|  805   return pParent->xCurrentTime(pParent, pTimeOut); |  | 
|  806 } |  | 
|  807  |  | 
|  808 /* |  | 
|  809 ** This procedure registers the fs vfs with SQLite. If the argument is |  | 
|  810 ** true, the fs vfs becomes the new default vfs. It is the only publicly |  | 
|  811 ** available function in this file. |  | 
|  812 */ |  | 
|  813 int fs_register(void){ |  | 
|  814   if( fs_vfs.pParent ) return SQLITE_OK; |  | 
|  815   fs_vfs.pParent = sqlite3_vfs_find(0); |  | 
|  816   fs_vfs.base.mxPathname = fs_vfs.pParent->mxPathname; |  | 
|  817   fs_vfs.base.szOsFile = MAX(sizeof(tmp_file), sizeof(fs_file)); |  | 
|  818   return sqlite3_vfs_register(&fs_vfs.base, 0); |  | 
|  819 } |  | 
|  820  |  | 
|  821 #ifdef SQLITE_TEST |  | 
|  822   int SqlitetestOnefile_Init() {return fs_register();} |  | 
|  823 #endif |  | 
| OLD | NEW |