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