|
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 ** $Id: test_onefile.c,v 1.9 2008/06/26 10:54:12 danielk1977 Exp $ |
|
14 ** |
|
15 ** 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 |
|
31 ** main memory (see pragma "temp_store" or the SQLITE_TEMP_STORE compile |
|
32 ** time option). |
|
33 ** |
|
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 |
|
84 #include "sqlite3.h" |
|
85 #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 |
|
99 typedef struct fs_real_file fs_real_file; |
|
100 struct 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 |
|
111 typedef struct fs_file fs_file; |
|
112 struct fs_file { |
|
113 sqlite3_file base; |
|
114 int eType; |
|
115 fs_real_file *pReal; |
|
116 }; |
|
117 |
|
118 typedef struct tmp_file tmp_file; |
|
119 struct 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 */ |
|
133 static int fsClose(sqlite3_file*); |
|
134 static int fsRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); |
|
135 static int fsWrite(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); |
|
136 static int fsTruncate(sqlite3_file*, sqlite3_int64 size); |
|
137 static int fsSync(sqlite3_file*, int flags); |
|
138 static int fsFileSize(sqlite3_file*, sqlite3_int64 *pSize); |
|
139 static int fsLock(sqlite3_file*, int); |
|
140 static int fsUnlock(sqlite3_file*, int); |
|
141 static int fsCheckReservedLock(sqlite3_file*, int *pResOut); |
|
142 static int fsFileControl(sqlite3_file*, int op, void *pArg); |
|
143 static int fsSectorSize(sqlite3_file*); |
|
144 static int fsDeviceCharacteristics(sqlite3_file*); |
|
145 |
|
146 /* |
|
147 ** Method declarations for tmp_file. |
|
148 */ |
|
149 static int tmpClose(sqlite3_file*); |
|
150 static int tmpRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); |
|
151 static int tmpWrite(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); |
|
152 static int tmpTruncate(sqlite3_file*, sqlite3_int64 size); |
|
153 static int tmpSync(sqlite3_file*, int flags); |
|
154 static int tmpFileSize(sqlite3_file*, sqlite3_int64 *pSize); |
|
155 static int tmpLock(sqlite3_file*, int); |
|
156 static int tmpUnlock(sqlite3_file*, int); |
|
157 static int tmpCheckReservedLock(sqlite3_file*, int *pResOut); |
|
158 static int tmpFileControl(sqlite3_file*, int op, void *pArg); |
|
159 static int tmpSectorSize(sqlite3_file*); |
|
160 static int tmpDeviceCharacteristics(sqlite3_file*); |
|
161 |
|
162 /* |
|
163 ** Method declarations for fs_vfs. |
|
164 */ |
|
165 static int fsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); |
|
166 static int fsDelete(sqlite3_vfs*, const char *zName, int syncDir); |
|
167 static int fsAccess(sqlite3_vfs*, const char *zName, int flags, int *); |
|
168 static int fsFullPathname(sqlite3_vfs*, const char *zName, int nOut,char *zOut); |
|
169 static void *fsDlOpen(sqlite3_vfs*, const char *zFilename); |
|
170 static void fsDlError(sqlite3_vfs*, int nByte, char *zErrMsg); |
|
171 static void *fsDlSym(sqlite3_vfs*,void*, const char *zSymbol); |
|
172 static void fsDlClose(sqlite3_vfs*, void*); |
|
173 static int fsRandomness(sqlite3_vfs*, int nByte, char *zOut); |
|
174 static int fsSleep(sqlite3_vfs*, int microseconds); |
|
175 static int fsCurrentTime(sqlite3_vfs*, double*); |
|
176 |
|
177 |
|
178 typedef struct fs_vfs_t fs_vfs_t; |
|
179 struct fs_vfs_t { |
|
180 sqlite3_vfs base; |
|
181 fs_real_file *pFileList; |
|
182 sqlite3_vfs *pParent; |
|
183 }; |
|
184 |
|
185 static 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 */ |
|
196 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 |
|
209 static 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 |
|
226 static 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 */ |
|
250 static 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 */ |
|
259 static 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 */ |
|
276 static 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 */ |
|
300 static 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 */ |
|
309 static 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 */ |
|
316 static 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 */ |
|
325 static int tmpLock(sqlite3_file *pFile, int eLock){ |
|
326 return SQLITE_OK; |
|
327 } |
|
328 |
|
329 /* |
|
330 ** Unlock a tmp-file. |
|
331 */ |
|
332 static 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 */ |
|
339 static int tmpCheckReservedLock(sqlite3_file *pFile, int *pResOut){ |
|
340 *pResOut = 0; |
|
341 return SQLITE_OK; |
|
342 } |
|
343 |
|
344 /* |
|
345 ** File control method. For custom operations on a tmp-file. |
|
346 */ |
|
347 static 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 */ |
|
354 static int tmpSectorSize(sqlite3_file *pFile){ |
|
355 return 0; |
|
356 } |
|
357 |
|
358 /* |
|
359 ** Return the device characteristic flags supported by a tmp-file. |
|
360 */ |
|
361 static int tmpDeviceCharacteristics(sqlite3_file *pFile){ |
|
362 return 0; |
|
363 } |
|
364 |
|
365 /* |
|
366 ** Close an fs-file. |
|
367 */ |
|
368 static 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 */ |
|
393 static 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 */ |
|
432 static 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 */ |
|
481 static 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 */ |
|
495 static 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 */ |
|
519 static 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 */ |
|
533 static int fsLock(sqlite3_file *pFile, int eLock){ |
|
534 return SQLITE_OK; |
|
535 } |
|
536 |
|
537 /* |
|
538 ** Unlock an fs-file. |
|
539 */ |
|
540 static 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 */ |
|
547 static int fsCheckReservedLock(sqlite3_file *pFile, int *pResOut){ |
|
548 *pResOut = 0; |
|
549 return SQLITE_OK; |
|
550 } |
|
551 |
|
552 /* |
|
553 ** File control method. For custom operations on an fs-file. |
|
554 */ |
|
555 static 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 */ |
|
562 static int fsSectorSize(sqlite3_file *pFile){ |
|
563 return BLOCKSIZE; |
|
564 } |
|
565 |
|
566 /* |
|
567 ** Return the device characteristic flags supported by an fs-file. |
|
568 */ |
|
569 static int fsDeviceCharacteristics(sqlite3_file *pFile){ |
|
570 return 0; |
|
571 } |
|
572 |
|
573 /* |
|
574 ** Open an fs file handle. |
|
575 */ |
|
576 static 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 |
|
657 open_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 */ |
|
677 static 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 */ |
|
703 static int fsAccess( |
|
704 sqlite3_vfs *pVfs, |
|
705 const char *zPath, |
|
706 int flags, |
|
707 int *pResOut |
|
708 ){ |
|
709 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; |
|
716 return pParent->xAccess(pParent, zPath, flags, pResOut); |
|
717 } |
|
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); |
|
727 |
|
728 *pResOut = (pReal && (!isJournal || pReal->nJournal>0)); |
|
729 return SQLITE_OK; |
|
730 } |
|
731 |
|
732 /* |
|
733 ** 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 */ |
|
737 static 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 ){ |
|
743 sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; |
|
744 return pParent->xFullPathname(pParent, zPath, nOut, zOut); |
|
745 } |
|
746 |
|
747 /* |
|
748 ** Open the dynamic library located at zPath and return a handle. |
|
749 */ |
|
750 static 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 */ |
|
760 static 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 */ |
|
768 static void *fsDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){ |
|
769 sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; |
|
770 return pParent->xDlSym(pParent, pHandle, zSymbol); |
|
771 } |
|
772 |
|
773 /* |
|
774 ** Close the dynamic library handle pHandle. |
|
775 */ |
|
776 static 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 */ |
|
785 static 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 */ |
|
794 static 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 */ |
|
802 static 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 */ |
|
812 int 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 |