SQLite4
Check-in [c8eb0a0cf4dbaef940af8a622f179a66779a2b41]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
SHA1 Hash:c8eb0a0cf4dbaef940af8a622f179a66779a2b41
Date: 2013-09-17 20:26:32
User: dan
Comment:Add new file bt_pager.c.
Tags And Properties
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/btInt.h

86
87
88
89
90
91
92



93
94
95
96

97
98
99
100
101
102
103
...
121
122
123
124
125
126
127
128
129
130
131

/*************************************************************************
** File-system interface.
*/
typedef struct bt_env bt_env;
typedef struct bt_file bt_file;




struct bt_env {
  void *pVfsCtx;
  int (*xFullpath)(sqlite4_env*,bt_env*, const char *, char **);
  int (*xOpen)(sqlite4_env*,bt_env*, const char *, int flags, bt_file**);

  int (*xRead)(bt_file*, i64, void *, int);
  int (*xWrite)(bt_file*, i64, void *, int);
  int (*xTruncate)(bt_file*, i64);
  int (*xSync)(bt_file*);
  int (*xSectorSize)(bt_file*);
  int (*xClose)(bt_file*);
  int (*xUnlink)(sqlite4_env*,bt_env*, const char *);
................................................................................

/* Find the default VFS */
bt_env *sqlite4BtEnvDefault(void);

/*
** End of file system interface.
*************************************************************************/











>
>
>




>







 







<



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
...
125
126
127
128
129
130
131

132
133
134

/*************************************************************************
** File-system interface.
*/
typedef struct bt_env bt_env;
typedef struct bt_file bt_file;

/*
** xFullpath:
*/
struct bt_env {
  void *pVfsCtx;
  int (*xFullpath)(sqlite4_env*,bt_env*, const char *, char **);
  int (*xOpen)(sqlite4_env*,bt_env*, const char *, int flags, bt_file**);
  int (*xSize)(bt_file*, i64*);
  int (*xRead)(bt_file*, i64, void *, int);
  int (*xWrite)(bt_file*, i64, void *, int);
  int (*xTruncate)(bt_file*, i64);
  int (*xSync)(bt_file*);
  int (*xSectorSize)(bt_file*);
  int (*xClose)(bt_file*);
  int (*xUnlink)(sqlite4_env*,bt_env*, const char *);
................................................................................

/* Find the default VFS */
bt_env *sqlite4BtEnvDefault(void);

/*
** End of file system interface.
*************************************************************************/




Added src/bt_pager.c

















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
/*
** 2013 September 14
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
*/

#include "btInt.h"

/* By default pages are 1024 bytes in size. */
#define BT_DEFAULT_PGSZ 1024

typedef struct BtPageHash BtPageHash;
typedef struct BtDbhdr BtDbhdr;

/*
** Hash table for page references currently in memory. Manipulated using
** the following functions:
**
**     btHashAdd()
**     btHashRemove()
**     btHashSearch()
**     btHashClear()
*/
struct BtPageHash {
  int nEntry;                     /* Number of entries in hash table */
  int nHash;                      /* Size of aHash[] array */
  BtPage **aHash;                 /* Hash array */
};

struct BtPage {
  BtPager *pPager;                /* Pager object that owns this page handle */
  u32 pgno;                       /* Current page number */
  int nRef;                       /* Number of references to this page */
  int flags;                      /* Mask of BTPAGE_XXX flags */
  u8 *aData;                      /* Pointer to current data */
  BtPage *pNextHash;              /* Next entry with same hash key */
  BtPage *pNextDirty;             /* Next page in BtPager.pDirty list */
};

/*
** Candidate values for BtPage.flags
*/
#define BT_PAGE_DIRTY 0x0001      /* Set for pages in BtPager.pDirty list */

/*
** Pager object.
*/
struct BtPager {
  sqlite4_env *pEnv;              /* SQLite environment */
  bt_env *pVfs;                   /* Bt environment */
  int iTransactionLevel;          /* Current transaction level (see bt.h) */
  char *zFile;                    /* Database file name */
  int nFile;                      /* Length of string zFile in bytes */
  bt_file *pFd;                   /* Database file */
  BtPageHash hash;                /* Hash table */
  BtPage *pDirty;                 /* List of all dirty pages */
};

/*
** Database header.
*/
struct BtDbhdr {
  u32 pgsz;                       /* Page size in bytes */
  u32 nPg;                        /* Number of pages in database */
  u32 cookie;                     /* User cookie value */
};



/**************************************************************************
** Interface to BtPageHash object.
*/

/*
** Return the hash key for page number pgno in a hash table with nHash
** buckets.
*/
static int hashkey(int nHash, u32 pgno){
  return (pgno % nHash);
}

/*
** Add page pPg to the hash table.
*/
static int btHashAdd(BtPager *p, BtPage *pPg){
  BtPage **pp;
  int h;

  /* If required, increase the number of buckets in the hash table. */
  if( p->hash.nEntry>=p->hash.nHash/2 ){
    int i;
    int nNew = (p->hash.nHash ? p->hash.nHash*2 : 256);
    BtPage **aNew;
    BtPage **aOld = p->hash.aHash;

    aNew = (BtPage **)sqlite4_malloc(p->pEnv, nNew*sizeof(BtPage*));
    if( aNew==0 ) return SQLITE4_NOMEM;
    memset(aNew, 0, nNew*sizeof(BtPage*));
    for(i=0; i<p->hash.nHash; i++){
      while( aOld[i] ){
        BtPage *pShift = aOld[i];
        aOld[i] = pShift->pNextHash;
        h = hashkey(nNew, pPg->pgno);
        pShift->pNextHash = aNew[h];
        aNew[h] = pShift;
      }
    }
    p->hash.aHash = aNew;
    p->hash.nHash = nNew;
    sqlite4_free(p->pEnv, aOld);
  }

  /* Add the new entry to the hash table. */
  assert( pPg->pNextHash==0 );
  h = hashkey(p->hash.nHash, pPg->pgno);
  pPg->pNextHash = p->hash.aHash[h];
  p->hash.aHash[h] = pPg;
  p->hash.nEntry++;
}

/*
** Remove page pPg from the hash table.
*/
static void btHashRemove(BtPager *p, BtPage *pPg){
  BtPage **pp;
  int h = hashkey(p->hash.nHash, pPg->pgno);
  for(pp=&p->hash.aHash[h]; *pp!=pPg; pp = &((*pp)->pNextHash));
  *pp = pPg->pNextHash;
  p->hash.nEntry--;
}

/*
** Search the hash table for a page with page number pgno. If found, return
** a pointer to the BtPage object. Otherwise, return NULL.
*/
static BtPage *btHashSearch(BtPager *p, u32 pgno){
  int h = hashkey(p->hash.nHash, pgno);
  BtPage *pRet;
  for(pRet=p->hash.aHash[h]; pRet && pRet->pgno!=pgno; pRet=pRet->pNextHash);
  return pRet;
}

/*
** Remove all entries from the hash-table. And free any allocations made
** by earlier calls to btHashAdd().
*/
static void btHashClear(BtPager *p){
  sqlite4_free(p->pEnv, p->hash.aHash);
  memset(&p->hash, 0, sizeof(BtPageHash));
}
/*
** End of BtPageHash object interface.
**************************************************************************/

/*
** Open a new pager database handle.
*/
int sqlite4BtPagerNew(sqlite4_env *pEnv, int nExtra, BtPager **pp){
  BtPager *p;
  int nByte;

  nByte = sizeof(BtPager) + nExtra;
  p = (BtPager*)sqlite4_malloc(pEnv, nByte);
  if( !p ) return SQLITE4_NOMEM; 
  memset(0, p, nByte);

  p->pEnv = pEnv;
  p->pVfs = sqlite4BtEnvDefault();
  *pp = p;
  return SQLITE4_OK;
}

/*
** Close a pager database handle.
*/
int sqlite4BtPagerClose(BtPager *p){
  if( p->pFd ){
    p->pVfs->xClose(p->pFd);
  }
  btHashClear(p);
  sqlite4_free(p->pEnv, p->zFile);
  sqlite4_free(p->pEnv, p);
  return SQLITE4_OK;
}

/*
** Return a pointer to the nExtra bytes of space allocated by PagerNew().
*/
void *sqlite4BtPagerExtra(BtPager *p){
  return (void*)&p[1];
}

/*
** Attach a database file to a pager object.
**
** This function may only be called once for each BtPager object. If it
** fails, the BtPager is rendered unusable (and must be closed by the
** caller using BtPagerClose()).
**
** If successful, SQLITE4_OK is returned. Otherwise, an SQLite error code.
*/
int sqlite4BtPagerOpen(BtPager *p, const char *zFilename){
  int flags = 0;                  /* Flags to pass to xOpen() */
  sqlite4_env *pEnv = p->pEnv;
  bt_env *pVfs = p->pVfs;

  assert( p->pFd==0 && p->zFilename==0 );

  rc = pVfs->xFullpath(pEnv, pVfs, zFilename, &p->zFile);
  if( rc==SQLITE4_OK ){
    p->nFile = strlen(p->zFile);
    rc = pVfs->xOpen(pEnv, pVfs, zFilename, flags, &p->pFd);
  }

  assert( (rc==SQLITE4_OK)==(p->pFd!=0) );
  return rc;
}

/*
** Open a read-transaction.
*/
static int btOpenReadTransaction(BtPager *p){
  int rc;
  i64 nByte;                      /* Size of db file in bytes */

  assert( p->iTransactionLevel==0 );
  assert( p->pFd );

  rc = p->pVfs->xSize(p->pFd, &nByte);
  if( rc==SQLITE4_OK && nByte>0 ){
    rc = p->pVfs->xRead(p->pFd, 0, &p->dbhdr, sizeof(p->dbhdr));
  }else{
    memset(&p->dbhdr, 0, sizeof(p->dbhdr));
    p->dbhdr.pgsz = BT_DEFAULT_PGSZ;
  }

  return rc;
}

static int btCommitTransaction(BtPager *p){
  int rc = SQLITE4_OK;
  BtPage *pPg;
  BtPage *pNext;
  assert( p->iTransactionLevel>=2 );

  for(pPg=p->pDirty; pPg; pPg=pNext){
    pNext = pPg->pNextDirty;
    pPg->flags &= ~(BT_PAGE_DIRTY);
    pPg->pNextDirty = 0;
    if( rc==SQLITE4_OK ){
      i64 iOff = (i64)p->dbhdr.pgsz * (i64)(pPg->pgno-1);
      rc = p->pVfs->xWrite(p->pFd, iOff, pPg->aData, p->dbhdr.pgsz);
    }
  }
  p->pDirty = 0;

  if( rc==SQLITE4_OK ){
    rc = p->pVfs->xWrite(p->pFd, 0, (void*)&p->dbhdr, sizeof(BtDbhdr));
  }

  return rc;
}

/*
** Transactions. These methods are more or less the same as their 
** counterparts in bt.h.
*/
int sqlite4BtPagerBegin(BtPager *p, int iLevel){
  int rc = SQLITE4_OK;
  assert( p->pFd );

  if( p->iTransactionLevel<iLevel ){
    /* Open a read transaction if one is not already open */
    if( p->iTransactionLevel==0 ){
      rc = btOpenReadTransaction(p);
    }

    if( rc==SQLITE4_OK ){
      assert( p->iTransactionLevel>=1 && iLevel>=p->iTransactionLevel );
      p->iTransactionLevel = iLevel;
    }
  }

  return rc;
}

int sqlite4BtPagerCommit(BtPager *p, int iLevel){
  int rc = SQLITE4_OK;

  assert( p->pFd );
  if( p->iTransactionLevel>=iLevel ){
    if( p->iTransactionLevel>=2 && iLevel<2 ){
      /* Commit the main write transaction. */
      rc = btCommitTransaction(p);
    }
    p->iTransactionLevel = iLevel;
  }
  return rc;
}

int sqlite4BtPagerRollback(BtPager *p, int iLevel){
  assert( p->pFd );
  if( p->iTransactionLevel>=iLevel ){
  }
}

int sqlite4BtPagerRevert(BtPager *p, int iLevel){
  assert( p->pFd );
  rc = sqlite4BtPagerRollback(p, iLevel);
  if( rc==SQLITE4_OK && iLevel>=2 && p->iTransactionLevel==iLevel ){
    /* Rollback (but do not close) transaction iLevel */
  }
}

/*
** Return the current transaction level.
*/
int sqlite4BtPagerTransactionLevel(BtPager *p){
  return p->iTransactionLevel;
}

/*
** Query for the database page size. Requires an open read transaction.
*/
int sqlite4BtPagerPagesize(BtPager *p, int *pnByte){
  assert( p->iTransactionLevel>=1 && p->pFd );
  *pnByte = (int)p->dbhdr.pgsz;
  return SQLITE4_OK;
}

/* 
** Query for the root page number. Requires an open read transaction.
*/
int sqlite4BtPagerRootpgno(BtPager *p, u32 *piRoot){
  assert( p->iTransactionLevel>=1 && p->pFd );
  *piRoot = 2;
  return SQLITE4_OK;
}

static int btAllocatePage(BtPager *p, BtPage **ppPg){
  BtPage *pRet;
  u8 *aData;

  pRet = (BtPage*)sqlite4_malloc(p->pEnv, sizeof(BtPage));
  aData = (u8*)sqlite4_malloc(p->pEnv, p->dbhdr.pgsz);

  if( pRet && aData ){
    memset(pRet, 0, sizeof(BtPage));
    pRet->aData = aData;
    pRet->pPager = p;
    rc = SQLITE4_OK;
  }else{
    sqlite4_free(p->pEnv, pRet);
    sqlite4_free(p->pEnv, aData);
    rc = SQLITE4_NOMEM;
    pRet = 0;
  }

  *ppPg = pRet;
  return rc;
}

static void btFreePage(BtPager *p, BtPage *pPg){
  if( pPg ){
    sqlite4_free(p->pEnv, pPg->aData);
    sqlite4_free(p->pEnv, pPg);
  }
}

/*
** Read, write and trim existing database pages.
*/
int sqlite4BtPageGet(BtPager *p, u32 pgno, BtPage **ppPg){
  int rc = SQLITE4_OK;            /* Return code */
  BtPage *pRet;                   /* Returned page handle */

  /* Search the cache for an existing page. */
  pRet = btHashSearch(p, pgno);

  /* If the page is not in the cache, load it from disk */
  if( pRet==0 ){
    rc = btAllocatePage(p, &pRet);
    if( rc==SQLITE4_OK ){
      pRet->pgno = pgno;
      if( pgno<=p->dbhdr.nPg ){
        i64 iOff = (i64)p->dbhdr.pgsz * (i64)(pgno-1);
        rc = p->pVfs->xRead(p->pFd, iOff, pRet->aData, p->dbhdr.pgsz);
      }else{
        memset(pRet->aData, 0, p->dbhdr.pgsz);
      }

      if( rc==SQLITE4_OK ){
        rc = btHashAdd(p, pRet);
      }
      if( rc!=SQLITE4_OK ){
        btFreePage(p, pRet);
        pRet = 0;
      }
    }
  }

  if( rc==SQLITE4_OK ){
    pRet->nRef++;
    *ppPg = pRet;
  }
  return rc;
}

int sqlite4BtPageWrite(BtPage *pPg){
  if( (pPg->flags & BT_PAGE_DIRTY)==0 ){
    pPg->flags |= BT_PAGE_DIRTY;
    pPg->pNextDirty = pPg->pPager->pDirty;
    pPg->pPager->pDirty = pPg;
  }
  return SQLITE4_OK;
}

int sqlite4BtPageTrim(BtPage *pPg){
  assert( !"todo" );
  return SQLITE4_OK;
}

int sqlite4BtPageRelease(BtPage *pPg){
  assert( pPg->nRef>=1 );
  pPg->nRef--;
  return SQLITE4_OK;
}

/*
** Allocate a new database page and return a writable reference to it.
*/
int sqlite4BtPageAllocate(BtPager *p, BtPage **ppPg){
  BtPage *pPg = 0;
  int rc;
  u32 pgno = p->dbhdr.nPg;

  rc = sqlite4BtPageGet(p, pgno, &pPg);
  if( rc==SQLITE4_OK ){
    rc = sqlite4BtPageWrite(pPg);
    if( rc!=SQLITE4_OK ){
      sqlite4BtPageRelease(pPg);
      pPg = 0;
    }else{
      p->dbhdr.nPg = pgno+1;
    }
  }

  *ppPg = pPg;
  return rc;
}

/*
** Return the current page number of the argument page reference.
*/
u32 sqlite4BtPagePgno(BtPage *pPg){
  return pPg->pgno;
}

/*
** Return a pointer to the data buffer associated with page pPg.
*/
void *sqlite4BtPageData(BtPage *pPg){
  return pPg->aData;
}

/* 
** Read the schema cookie value. Requires an open read-transaction.
*/
int sqlite4BtPagerSetCookie(BtPager *p, u32 iVal){
  assert( p->iTransactionLevel>=2 );
  p->dbhdr.cookie = iVal;
}

/* 
** Set the schema cookie value. Requires an open write-transaction.
*/
int sqlite4BtPagerGetCookie(BtPager *p, u32 *piVal){
  assert( p->iTransactionLevel>=1 );
  *piVal = p->dbhdr.cookie;
}

Changes to src/bt_unix.c

122
123
124
125
126
127
128














129
130
131
132
133
134
135
...
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
...
419
420
421
422
423
424
425

426
427
428
429
430
431
432
      rc = btErrorBkpt(SQLITE4_IOERR);
    }
  }

  *ppFile = (bt_file*)p;
  return rc;
}















static int btPosixOsWrite(
  bt_file *pFile,                 /* File to write to */
  i64 iOff,                       /* Offset to write to */
  void *pData,                    /* Write data from this buffer */
  int nData                       /* Bytes of data to write */
){
................................................................................
  }else{
    ssize_t prc = read(p->fd, pData, (size_t)nData);
    if( prc<0 ){ 
      rc = btErrorBkpt(SQLITE4_IOERR);
    }else if( prc<nData ){
      memset(&((u8 *)pData)[prc], 0, nData - prc);
    }

  }

  return rc;
}

static int btPosixOsSync(bt_file *pFile){
  int rc = SQLITE4_OK;
................................................................................
}

bt_env *sqlite4BtEnvDefault(void){
  static bt_env posix_env = {
    0,                            /* pVfsCtx */
    btPosixOsFullpath,            /* xFullpath */
    btPosixOsOpen,                /* xOpen */

    btPosixOsRead,                /* xRead */
    btPosixOsWrite,               /* xWrite */
    btPosixOsTruncate,            /* xTruncate */
    btPosixOsSync,                /* xSync */
    btPosixOsSectorSize,          /* xSectorSize */
    btPosixOsClose,               /* xClose */
    btPosixOsUnlink,              /* xUnlink */







>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







<







 







>







122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
...
196
197
198
199
200
201
202

203
204
205
206
207
208
209
...
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
      rc = btErrorBkpt(SQLITE4_IOERR);
    }
  }

  *ppFile = (bt_file*)p;
  return rc;
}

static int btPosixOsSize(bt_file *pFile, i64 *pnByte){
  int rc = SQLITE4_OK;
  PosixFile *p = (PosixFile *)pFile;
  struct stat sBuf;

  if( fstat(p->fd, &sBuf)!=0 ){
    rc = SQLITE4_IOERR_FSTAT;
  }else{
    *pnByte = sBuf.st_size;
  }

  return rc;
}

static int btPosixOsWrite(
  bt_file *pFile,                 /* File to write to */
  i64 iOff,                       /* Offset to write to */
  void *pData,                    /* Write data from this buffer */
  int nData                       /* Bytes of data to write */
){
................................................................................
  }else{
    ssize_t prc = read(p->fd, pData, (size_t)nData);
    if( prc<0 ){ 
      rc = btErrorBkpt(SQLITE4_IOERR);
    }else if( prc<nData ){
      memset(&((u8 *)pData)[prc], 0, nData - prc);
    }

  }

  return rc;
}

static int btPosixOsSync(bt_file *pFile){
  int rc = SQLITE4_OK;
................................................................................
}

bt_env *sqlite4BtEnvDefault(void){
  static bt_env posix_env = {
    0,                            /* pVfsCtx */
    btPosixOsFullpath,            /* xFullpath */
    btPosixOsOpen,                /* xOpen */
    btPosixOsSize,                /* xSize */
    btPosixOsRead,                /* xRead */
    btPosixOsWrite,               /* xWrite */
    btPosixOsTruncate,            /* xTruncate */
    btPosixOsSync,                /* xSync */
    btPosixOsSectorSize,          /* xSectorSize */
    btPosixOsClose,               /* xClose */
    btPosixOsUnlink,              /* xUnlink */