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