OLD | NEW |
| (Empty) |
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 = (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 */ | |
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 */ | |
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 = (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 */ | |
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 */ | |
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 */ | |
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 = (int)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 = (int)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 = (int)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 = (int)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 | |
OLD | NEW |