Annotation of embedaddon/sqlite3/src/test_onefile.c, revision 1.1.1.1
1.1 misho 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: */
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: */
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: */
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 = 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 = MAX(pTmp->nSize, iOfst+iAmt);
301: return SQLITE_OK;
302: }
303:
304: /*
305: ** Truncate a tmp-file.
306: */
307: static int tmpTruncate(sqlite3_file *pFile, sqlite_int64 size){
308: tmp_file *pTmp = (tmp_file *)pFile;
309: pTmp->nSize = MIN(pTmp->nSize, size);
310: return SQLITE_OK;
311: }
312:
313: /*
314: ** Sync a tmp-file.
315: */
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: */
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: */
332: static int tmpLock(sqlite3_file *pFile, int eLock){
333: return SQLITE_OK;
334: }
335:
336: /*
337: ** Unlock a tmp-file.
338: */
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: */
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: */
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: */
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: */
368: static int tmpDeviceCharacteristics(sqlite3_file *pFile){
369: return 0;
370: }
371:
372: /*
373: ** Close an fs-file.
374: */
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: */
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 = 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: */
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 = MAX(pReal->nDatabase, iAmt+iOfst);
457: }
458: }
459: }else{
460: /* Journal file. */
461: int iRem = iAmt;
462: int iBuf = 0;
463: int ii = 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 = MAX(pReal->nJournal, iAmt+iOfst);
479: }
480: }
481:
482: return rc;
483: }
484:
485: /*
486: ** Truncate an fs-file.
487: */
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 = MIN(pReal->nDatabase, size);
493: }else{
494: pReal->nJournal = MIN(pReal->nJournal, size);
495: }
496: return SQLITE_OK;
497: }
498:
499: /*
500: ** Sync an fs-file.
501: */
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] = (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: */
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: */
540: static int fsLock(sqlite3_file *pFile, int eLock){
541: return SQLITE_OK;
542: }
543:
544: /*
545: ** Unlock an fs-file.
546: */
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: */
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: */
562: static int fsFileControl(sqlite3_file *pFile, int op, void *pArg){
563: return SQLITE_OK;
564: }
565:
566: /*
567: ** Return the sector-size in bytes for an fs-file.
568: */
569: static int fsSectorSize(sqlite3_file *pFile){
570: return BLOCKSIZE;
571: }
572:
573: /*
574: ** Return the device characteristic flags supported by an fs-file.
575: */
576: static int fsDeviceCharacteristics(sqlite3_file *pFile){
577: return 0;
578: }
579:
580: /*
581: ** Open an fs file handle.
582: */
583: static int fsOpen(
584: sqlite3_vfs *pVfs,
585: const char *zName,
586: sqlite3_file *pFile,
587: int flags,
588: int *pOutFlags
589: ){
590: fs_vfs_t *pFsVfs = (fs_vfs_t *)pVfs;
591: fs_file *p = (fs_file *)pFile;
592: fs_real_file *pReal = 0;
593: int eType;
594: int nName;
595: int rc = SQLITE_OK;
596:
597: if( 0==(flags&(SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_MAIN_JOURNAL)) ){
598: tmp_file *p = (tmp_file *)pFile;
599: memset(p, 0, sizeof(*p));
600: p->base.pMethods = &tmp_io_methods;
601: return SQLITE_OK;
602: }
603:
604: eType = ((flags&(SQLITE_OPEN_MAIN_DB))?DATABASE_FILE:JOURNAL_FILE);
605: p->base.pMethods = &fs_io_methods;
606: p->eType = eType;
607:
608: assert(strlen("-journal")==8);
609: nName = strlen(zName)-((eType==JOURNAL_FILE)?8:0);
610: pReal=pFsVfs->pFileList;
611: for(; pReal && strncmp(pReal->zName, zName, nName); pReal=pReal->pNext);
612:
613: if( !pReal ){
614: int real_flags = (flags&~(SQLITE_OPEN_MAIN_DB))|SQLITE_OPEN_TEMP_DB;
615: sqlite3_int64 size;
616: sqlite3_file *pRealFile;
617: sqlite3_vfs *pParent = pFsVfs->pParent;
618: assert(eType==DATABASE_FILE);
619:
620: pReal = (fs_real_file *)sqlite3_malloc(sizeof(*pReal)+pParent->szOsFile);
621: if( !pReal ){
622: rc = SQLITE_NOMEM;
623: goto open_out;
624: }
625: memset(pReal, 0, sizeof(*pReal)+pParent->szOsFile);
626: pReal->zName = zName;
627: pReal->pFile = (sqlite3_file *)(&pReal[1]);
628:
629: rc = pParent->xOpen(pParent, zName, pReal->pFile, real_flags, pOutFlags);
630: if( rc!=SQLITE_OK ){
631: goto open_out;
632: }
633: pRealFile = pReal->pFile;
634:
635: rc = pRealFile->pMethods->xFileSize(pRealFile, &size);
636: if( rc!=SQLITE_OK ){
637: goto open_out;
638: }
639: if( size==0 ){
640: rc = pRealFile->pMethods->xWrite(pRealFile, "\0", 1, BLOBSIZE-1);
641: pReal->nBlob = BLOBSIZE;
642: }else{
643: unsigned char zS[4];
644: pReal->nBlob = size;
645: rc = pRealFile->pMethods->xRead(pRealFile, zS, 4, 0);
646: pReal->nDatabase = (zS[0]<<24)+(zS[1]<<16)+(zS[2]<<8)+zS[3];
647: if( rc==SQLITE_OK ){
648: rc = pRealFile->pMethods->xRead(pRealFile, zS, 4, pReal->nBlob-4);
649: if( zS[0] || zS[1] || zS[2] || zS[3] ){
650: pReal->nJournal = pReal->nBlob;
651: }
652: }
653: }
654:
655: if( rc==SQLITE_OK ){
656: pReal->pNext = pFsVfs->pFileList;
657: if( pReal->pNext ){
658: pReal->pNext->ppThis = &pReal->pNext;
659: }
660: pReal->ppThis = &pFsVfs->pFileList;
661: pFsVfs->pFileList = pReal;
662: }
663: }
664:
665: open_out:
666: if( pReal ){
667: if( rc==SQLITE_OK ){
668: p->pReal = pReal;
669: pReal->nRef++;
670: }else{
671: if( pReal->pFile->pMethods ){
672: pReal->pFile->pMethods->xClose(pReal->pFile);
673: }
674: sqlite3_free(pReal);
675: }
676: }
677: return rc;
678: }
679:
680: /*
681: ** Delete the file located at zPath. If the dirSync argument is true,
682: ** ensure the file-system modifications are synced to disk before
683: ** returning.
684: */
685: static int fsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
686: int rc = SQLITE_OK;
687: fs_vfs_t *pFsVfs = (fs_vfs_t *)pVfs;
688: fs_real_file *pReal;
689: sqlite3_file *pF;
690: int nName = strlen(zPath) - 8;
691:
692: assert(strlen("-journal")==8);
693: assert(strcmp("-journal", &zPath[nName])==0);
694:
695: pReal = pFsVfs->pFileList;
696: for(; pReal && strncmp(pReal->zName, zPath, nName); pReal=pReal->pNext);
697: if( pReal ){
698: pF = pReal->pFile;
699: rc = pF->pMethods->xWrite(pF, "\0\0\0\0", 4, pReal->nBlob-BLOCKSIZE);
700: if( rc==SQLITE_OK ){
701: pReal->nJournal = 0;
702: }
703: }
704: return rc;
705: }
706:
707: /*
708: ** Test for access permissions. Return true if the requested permission
709: ** is available, or false otherwise.
710: */
711: static int fsAccess(
712: sqlite3_vfs *pVfs,
713: const char *zPath,
714: int flags,
715: int *pResOut
716: ){
717: fs_vfs_t *pFsVfs = (fs_vfs_t *)pVfs;
718: fs_real_file *pReal;
719: int isJournal = 0;
720: int nName = strlen(zPath);
721:
722: if( flags!=SQLITE_ACCESS_EXISTS ){
723: sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
724: return pParent->xAccess(pParent, zPath, flags, pResOut);
725: }
726:
727: assert(strlen("-journal")==8);
728: if( nName>8 && strcmp("-journal", &zPath[nName-8])==0 ){
729: nName -= 8;
730: isJournal = 1;
731: }
732:
733: pReal = pFsVfs->pFileList;
734: for(; pReal && strncmp(pReal->zName, zPath, nName); pReal=pReal->pNext);
735:
736: *pResOut = (pReal && (!isJournal || pReal->nJournal>0));
737: return SQLITE_OK;
738: }
739:
740: /*
741: ** Populate buffer zOut with the full canonical pathname corresponding
742: ** to the pathname in zPath. zOut is guaranteed to point to a buffer
743: ** of at least (FS_MAX_PATHNAME+1) bytes.
744: */
745: static int fsFullPathname(
746: sqlite3_vfs *pVfs, /* Pointer to vfs object */
747: const char *zPath, /* Possibly relative input path */
748: int nOut, /* Size of output buffer in bytes */
749: char *zOut /* Output buffer */
750: ){
751: sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
752: return pParent->xFullPathname(pParent, zPath, nOut, zOut);
753: }
754:
755: /*
756: ** Open the dynamic library located at zPath and return a handle.
757: */
758: static void *fsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
759: sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
760: return pParent->xDlOpen(pParent, zPath);
761: }
762:
763: /*
764: ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
765: ** utf-8 string describing the most recent error encountered associated
766: ** with dynamic libraries.
767: */
768: static void fsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
769: sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
770: pParent->xDlError(pParent, nByte, zErrMsg);
771: }
772:
773: /*
774: ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
775: */
776: static void (*fsDlSym(sqlite3_vfs *pVfs, void *pH, const char *zSym))(void){
777: sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
778: return pParent->xDlSym(pParent, pH, zSym);
779: }
780:
781: /*
782: ** Close the dynamic library handle pHandle.
783: */
784: static void fsDlClose(sqlite3_vfs *pVfs, void *pHandle){
785: sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
786: pParent->xDlClose(pParent, pHandle);
787: }
788:
789: /*
790: ** Populate the buffer pointed to by zBufOut with nByte bytes of
791: ** random data.
792: */
793: static int fsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
794: sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
795: return pParent->xRandomness(pParent, nByte, zBufOut);
796: }
797:
798: /*
799: ** Sleep for nMicro microseconds. Return the number of microseconds
800: ** actually slept.
801: */
802: static int fsSleep(sqlite3_vfs *pVfs, int nMicro){
803: sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
804: return pParent->xSleep(pParent, nMicro);
805: }
806:
807: /*
808: ** Return the current time as a Julian Day number in *pTimeOut.
809: */
810: static int fsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
811: sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
812: return pParent->xCurrentTime(pParent, pTimeOut);
813: }
814:
815: /*
816: ** This procedure registers the fs vfs with SQLite. If the argument is
817: ** true, the fs vfs becomes the new default vfs. It is the only publicly
818: ** available function in this file.
819: */
820: int fs_register(void){
821: if( fs_vfs.pParent ) return SQLITE_OK;
822: fs_vfs.pParent = sqlite3_vfs_find(0);
823: fs_vfs.base.mxPathname = fs_vfs.pParent->mxPathname;
824: fs_vfs.base.szOsFile = MAX(sizeof(tmp_file), sizeof(fs_file));
825: return sqlite3_vfs_register(&fs_vfs.base, 0);
826: }
827:
828: #ifdef SQLITE_TEST
829: int SqlitetestOnefile_Init() {return fs_register();}
830: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>