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