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