diff options
Diffstat (limited to 'libraries/sqlite/unix/sqlite-3.5.1/src/test_onefile.c')
-rw-r--r-- | libraries/sqlite/unix/sqlite-3.5.1/src/test_onefile.c | 825 |
1 files changed, 825 insertions, 0 deletions
diff --git a/libraries/sqlite/unix/sqlite-3.5.1/src/test_onefile.c b/libraries/sqlite/unix/sqlite-3.5.1/src/test_onefile.c new file mode 100644 index 0000000..d7e19de --- /dev/null +++ b/libraries/sqlite/unix/sqlite-3.5.1/src/test_onefile.c | |||
@@ -0,0 +1,825 @@ | |||
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 TEMP_STORE compile time | ||
30 | ** 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*); | ||
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*); | ||
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); | ||
166 | static int fsGetTempname(sqlite3_vfs*, int nOut, char *zOut); | ||
167 | static int fsFullPathname(sqlite3_vfs*, const char *zName, int nOut,char *zOut); | ||
168 | static void *fsDlOpen(sqlite3_vfs*, const char *zFilename); | ||
169 | static void fsDlError(sqlite3_vfs*, int nByte, char *zErrMsg); | ||
170 | static void *fsDlSym(sqlite3_vfs*,void*, const char *zSymbol); | ||
171 | static void fsDlClose(sqlite3_vfs*, void*); | ||
172 | static int fsRandomness(sqlite3_vfs*, int nByte, char *zOut); | ||
173 | static int fsSleep(sqlite3_vfs*, int microseconds); | ||
174 | static int fsCurrentTime(sqlite3_vfs*, double*); | ||
175 | |||
176 | |||
177 | typedef struct fs_vfs_t fs_vfs_t; | ||
178 | struct fs_vfs_t { | ||
179 | sqlite3_vfs base; | ||
180 | fs_real_file *pFileList; | ||
181 | sqlite3_vfs *pParent; | ||
182 | }; | ||
183 | |||
184 | static fs_vfs_t fs_vfs = { | ||
185 | { | ||
186 | 1, /* iVersion */ | ||
187 | 0, /* szOsFile */ | ||
188 | 0, /* mxPathname */ | ||
189 | 0, /* pNext */ | ||
190 | FS_VFS_NAME, /* zName */ | ||
191 | 0, /* pAppData */ | ||
192 | fsOpen, /* xOpen */ | ||
193 | fsDelete, /* xDelete */ | ||
194 | fsAccess, /* xAccess */ | ||
195 | fsGetTempname, /* xGetTempName */ | ||
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){ | ||
340 | return SQLITE_OK; | ||
341 | } | ||
342 | |||
343 | /* | ||
344 | ** File control method. For custom operations on a tmp-file. | ||
345 | */ | ||
346 | static int tmpFileControl(sqlite3_file *pFile, int op, void *pArg){ | ||
347 | return SQLITE_OK; | ||
348 | } | ||
349 | |||
350 | /* | ||
351 | ** Return the sector-size in bytes for a tmp-file. | ||
352 | */ | ||
353 | static int tmpSectorSize(sqlite3_file *pFile){ | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | /* | ||
358 | ** Return the device characteristic flags supported by a tmp-file. | ||
359 | */ | ||
360 | static int tmpDeviceCharacteristics(sqlite3_file *pFile){ | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | /* | ||
365 | ** Close an fs-file. | ||
366 | */ | ||
367 | static int fsClose(sqlite3_file *pFile){ | ||
368 | int rc = SQLITE_OK; | ||
369 | fs_file *p = (fs_file *)pFile; | ||
370 | fs_real_file *pReal = p->pReal; | ||
371 | |||
372 | /* Decrement the real_file ref-count. */ | ||
373 | pReal->nRef--; | ||
374 | assert(pReal->nRef>=0); | ||
375 | |||
376 | /* When the ref-count reaches 0, destroy the structure */ | ||
377 | if( pReal->nRef==0 ){ | ||
378 | *pReal->ppThis = pReal->pNext; | ||
379 | if( pReal->pNext ){ | ||
380 | pReal->pNext->ppThis = pReal->ppThis; | ||
381 | } | ||
382 | rc = pReal->pFile->pMethods->xClose(pReal->pFile); | ||
383 | sqlite3_free(pReal); | ||
384 | } | ||
385 | |||
386 | return rc; | ||
387 | } | ||
388 | |||
389 | /* | ||
390 | ** Read data from an fs-file. | ||
391 | */ | ||
392 | static int fsRead( | ||
393 | sqlite3_file *pFile, | ||
394 | void *zBuf, | ||
395 | int iAmt, | ||
396 | sqlite_int64 iOfst | ||
397 | ){ | ||
398 | int rc = SQLITE_OK; | ||
399 | fs_file *p = (fs_file *)pFile; | ||
400 | fs_real_file *pReal = p->pReal; | ||
401 | sqlite3_file *pF = pReal->pFile; | ||
402 | |||
403 | if( (p->eType==DATABASE_FILE && (iAmt+iOfst)>pReal->nDatabase) | ||
404 | || (p->eType==JOURNAL_FILE && (iAmt+iOfst)>pReal->nJournal) | ||
405 | ){ | ||
406 | rc = SQLITE_IOERR_SHORT_READ; | ||
407 | }else if( p->eType==DATABASE_FILE ){ | ||
408 | rc = pF->pMethods->xRead(pF, zBuf, iAmt, iOfst+BLOCKSIZE); | ||
409 | }else{ | ||
410 | /* Journal file. */ | ||
411 | int iRem = iAmt; | ||
412 | int iBuf = 0; | ||
413 | int ii = iOfst; | ||
414 | while( iRem>0 && rc==SQLITE_OK ){ | ||
415 | int iRealOff = pReal->nBlob - BLOCKSIZE*((ii/BLOCKSIZE)+1) + ii%BLOCKSIZE; | ||
416 | int iRealAmt = MIN(iRem, BLOCKSIZE - (iRealOff%BLOCKSIZE)); | ||
417 | |||
418 | rc = pF->pMethods->xRead(pF, &((char *)zBuf)[iBuf], iRealAmt, iRealOff); | ||
419 | ii += iRealAmt; | ||
420 | iBuf += iRealAmt; | ||
421 | iRem -= iRealAmt; | ||
422 | } | ||
423 | } | ||
424 | |||
425 | return rc; | ||
426 | } | ||
427 | |||
428 | /* | ||
429 | ** Write data to an fs-file. | ||
430 | */ | ||
431 | static int fsWrite( | ||
432 | sqlite3_file *pFile, | ||
433 | const void *zBuf, | ||
434 | int iAmt, | ||
435 | sqlite_int64 iOfst | ||
436 | ){ | ||
437 | int rc = SQLITE_OK; | ||
438 | fs_file *p = (fs_file *)pFile; | ||
439 | fs_real_file *pReal = p->pReal; | ||
440 | sqlite3_file *pF = pReal->pFile; | ||
441 | |||
442 | if( p->eType==DATABASE_FILE ){ | ||
443 | if( (iAmt+iOfst+BLOCKSIZE)>(pReal->nBlob-pReal->nJournal) ){ | ||
444 | rc = SQLITE_FULL; | ||
445 | }else{ | ||
446 | rc = pF->pMethods->xWrite(pF, zBuf, iAmt, iOfst+BLOCKSIZE); | ||
447 | if( rc==SQLITE_OK ){ | ||
448 | pReal->nDatabase = MAX(pReal->nDatabase, iAmt+iOfst); | ||
449 | } | ||
450 | } | ||
451 | }else{ | ||
452 | /* Journal file. */ | ||
453 | int iRem = iAmt; | ||
454 | int iBuf = 0; | ||
455 | int ii = iOfst; | ||
456 | while( iRem>0 && rc==SQLITE_OK ){ | ||
457 | int iRealOff = pReal->nBlob - BLOCKSIZE*((ii/BLOCKSIZE)+1) + ii%BLOCKSIZE; | ||
458 | int iRealAmt = MIN(iRem, BLOCKSIZE - (iRealOff%BLOCKSIZE)); | ||
459 | |||
460 | if( iRealOff<(pReal->nDatabase+BLOCKSIZE) ){ | ||
461 | rc = SQLITE_FULL; | ||
462 | }else{ | ||
463 | rc = pF->pMethods->xWrite(pF, &((char *)zBuf)[iBuf], iRealAmt,iRealOff); | ||
464 | ii += iRealAmt; | ||
465 | iBuf += iRealAmt; | ||
466 | iRem -= iRealAmt; | ||
467 | } | ||
468 | } | ||
469 | if( rc==SQLITE_OK ){ | ||
470 | pReal->nJournal = MAX(pReal->nJournal, iAmt+iOfst); | ||
471 | } | ||
472 | } | ||
473 | |||
474 | return rc; | ||
475 | } | ||
476 | |||
477 | /* | ||
478 | ** Truncate an fs-file. | ||
479 | */ | ||
480 | static int fsTruncate(sqlite3_file *pFile, sqlite_int64 size){ | ||
481 | fs_file *p = (fs_file *)pFile; | ||
482 | fs_real_file *pReal = p->pReal; | ||
483 | if( p->eType==DATABASE_FILE ){ | ||
484 | pReal->nDatabase = MIN(pReal->nDatabase, size); | ||
485 | }else{ | ||
486 | pReal->nJournal = MIN(pReal->nJournal, size); | ||
487 | } | ||
488 | return SQLITE_OK; | ||
489 | } | ||
490 | |||
491 | /* | ||
492 | ** Sync an fs-file. | ||
493 | */ | ||
494 | static int fsSync(sqlite3_file *pFile, int flags){ | ||
495 | fs_file *p = (fs_file *)pFile; | ||
496 | fs_real_file *pReal = p->pReal; | ||
497 | sqlite3_file *pRealFile = pReal->pFile; | ||
498 | int rc = SQLITE_OK; | ||
499 | |||
500 | if( p->eType==DATABASE_FILE ){ | ||
501 | unsigned char zSize[4]; | ||
502 | zSize[0] = (pReal->nDatabase&0xFF000000)>>24; | ||
503 | zSize[1] = (pReal->nDatabase&0x00FF0000)>>16; | ||
504 | zSize[2] = (pReal->nDatabase&0x0000FF00)>>8; | ||
505 | zSize[3] = (pReal->nDatabase&0x000000FF); | ||
506 | rc = pRealFile->pMethods->xWrite(pRealFile, zSize, 4, 0); | ||
507 | } | ||
508 | if( rc==SQLITE_OK ){ | ||
509 | rc = pRealFile->pMethods->xSync(pRealFile, flags&(~SQLITE_SYNC_DATAONLY)); | ||
510 | } | ||
511 | |||
512 | return rc; | ||
513 | } | ||
514 | |||
515 | /* | ||
516 | ** Return the current file-size of an fs-file. | ||
517 | */ | ||
518 | static int fsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ | ||
519 | fs_file *p = (fs_file *)pFile; | ||
520 | fs_real_file *pReal = p->pReal; | ||
521 | if( p->eType==DATABASE_FILE ){ | ||
522 | *pSize = pReal->nDatabase; | ||
523 | }else{ | ||
524 | *pSize = pReal->nJournal; | ||
525 | } | ||
526 | return SQLITE_OK; | ||
527 | } | ||
528 | |||
529 | /* | ||
530 | ** Lock an fs-file. | ||
531 | */ | ||
532 | static int fsLock(sqlite3_file *pFile, int eLock){ | ||
533 | return SQLITE_OK; | ||
534 | } | ||
535 | |||
536 | /* | ||
537 | ** Unlock an fs-file. | ||
538 | */ | ||
539 | static int fsUnlock(sqlite3_file *pFile, int eLock){ | ||
540 | return SQLITE_OK; | ||
541 | } | ||
542 | |||
543 | /* | ||
544 | ** Check if another file-handle holds a RESERVED lock on an fs-file. | ||
545 | */ | ||
546 | static int fsCheckReservedLock(sqlite3_file *pFile){ | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | /* | ||
551 | ** File control method. For custom operations on an fs-file. | ||
552 | */ | ||
553 | static int fsFileControl(sqlite3_file *pFile, int op, void *pArg){ | ||
554 | return SQLITE_OK; | ||
555 | } | ||
556 | |||
557 | /* | ||
558 | ** Return the sector-size in bytes for an fs-file. | ||
559 | */ | ||
560 | static int fsSectorSize(sqlite3_file *pFile){ | ||
561 | return BLOCKSIZE; | ||
562 | } | ||
563 | |||
564 | /* | ||
565 | ** Return the device characteristic flags supported by an fs-file. | ||
566 | */ | ||
567 | static int fsDeviceCharacteristics(sqlite3_file *pFile){ | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | /* | ||
572 | ** Open an fs file handle. | ||
573 | */ | ||
574 | static int fsOpen( | ||
575 | sqlite3_vfs *pVfs, | ||
576 | const char *zName, | ||
577 | sqlite3_file *pFile, | ||
578 | int flags, | ||
579 | int *pOutFlags | ||
580 | ){ | ||
581 | fs_vfs_t *pFsVfs = (fs_vfs_t *)pVfs; | ||
582 | fs_file *p = (fs_file *)pFile; | ||
583 | fs_real_file *pReal = 0; | ||
584 | int eType; | ||
585 | int nName; | ||
586 | int rc = SQLITE_OK; | ||
587 | |||
588 | if( 0==(flags&(SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_MAIN_JOURNAL)) ){ | ||
589 | tmp_file *p = (tmp_file *)pFile; | ||
590 | memset(p, 0, sizeof(*p)); | ||
591 | p->base.pMethods = &tmp_io_methods; | ||
592 | return SQLITE_OK; | ||
593 | } | ||
594 | |||
595 | eType = ((flags&(SQLITE_OPEN_MAIN_DB))?DATABASE_FILE:JOURNAL_FILE); | ||
596 | p->base.pMethods = &fs_io_methods; | ||
597 | p->eType = eType; | ||
598 | |||
599 | assert(strlen("-journal")==8); | ||
600 | nName = strlen(zName)-((eType==JOURNAL_FILE)?8:0); | ||
601 | pReal=pFsVfs->pFileList; | ||
602 | for(; pReal && strncmp(pReal->zName, zName, nName); pReal=pReal->pNext); | ||
603 | |||
604 | if( !pReal ){ | ||
605 | sqlite3_int64 size; | ||
606 | sqlite3_file *pRealFile; | ||
607 | sqlite3_vfs *pParent = pFsVfs->pParent; | ||
608 | assert(eType==DATABASE_FILE); | ||
609 | |||
610 | pReal = (fs_real_file *)sqlite3_malloc(sizeof(*pReal)+pParent->szOsFile); | ||
611 | if( !pReal ){ | ||
612 | rc = SQLITE_NOMEM; | ||
613 | goto open_out; | ||
614 | } | ||
615 | memset(pReal, 0, sizeof(*pReal)+pParent->szOsFile); | ||
616 | pReal->zName = zName; | ||
617 | pReal->pFile = (sqlite3_file *)(&pReal[1]); | ||
618 | |||
619 | rc = pParent->xOpen(pParent, zName, pReal->pFile, flags, pOutFlags); | ||
620 | if( rc!=SQLITE_OK ){ | ||
621 | goto open_out; | ||
622 | } | ||
623 | pRealFile = pReal->pFile; | ||
624 | |||
625 | rc = pRealFile->pMethods->xFileSize(pRealFile, &size); | ||
626 | if( rc!=SQLITE_OK ){ | ||
627 | goto open_out; | ||
628 | } | ||
629 | if( size==0 ){ | ||
630 | rc = pRealFile->pMethods->xWrite(pRealFile, "\0", 1, BLOBSIZE-1); | ||
631 | pReal->nBlob = BLOBSIZE; | ||
632 | }else{ | ||
633 | unsigned char zS[4]; | ||
634 | pReal->nBlob = size; | ||
635 | rc = pRealFile->pMethods->xRead(pRealFile, zS, 4, 0); | ||
636 | pReal->nDatabase = (zS[0]<<24)+(zS[1]<<16)+(zS[2]<<8)+zS[3]; | ||
637 | if( rc==SQLITE_OK ){ | ||
638 | rc = pRealFile->pMethods->xRead(pRealFile, zS, 4, pReal->nBlob-4); | ||
639 | if( zS[0] || zS[1] || zS[2] || zS[3] ){ | ||
640 | pReal->nJournal = pReal->nBlob; | ||
641 | } | ||
642 | } | ||
643 | } | ||
644 | |||
645 | if( rc==SQLITE_OK ){ | ||
646 | pReal->pNext = pFsVfs->pFileList; | ||
647 | if( pReal->pNext ){ | ||
648 | pReal->pNext->ppThis = &pReal->pNext; | ||
649 | } | ||
650 | pReal->ppThis = &pFsVfs->pFileList; | ||
651 | pFsVfs->pFileList = pReal; | ||
652 | } | ||
653 | } | ||
654 | |||
655 | open_out: | ||
656 | if( pReal ){ | ||
657 | if( rc==SQLITE_OK ){ | ||
658 | p->pReal = pReal; | ||
659 | pReal->nRef++; | ||
660 | }else{ | ||
661 | if( pReal->pFile->pMethods ){ | ||
662 | pReal->pFile->pMethods->xClose(pReal->pFile); | ||
663 | } | ||
664 | sqlite3_free(pReal); | ||
665 | } | ||
666 | } | ||
667 | return rc; | ||
668 | } | ||
669 | |||
670 | /* | ||
671 | ** Delete the file located at zPath. If the dirSync argument is true, | ||
672 | ** ensure the file-system modifications are synced to disk before | ||
673 | ** returning. | ||
674 | */ | ||
675 | static int fsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ | ||
676 | int rc = SQLITE_OK; | ||
677 | fs_vfs_t *pFsVfs = (fs_vfs_t *)pVfs; | ||
678 | fs_real_file *pReal; | ||
679 | sqlite3_file *pF; | ||
680 | int nName = strlen(zPath) - 8; | ||
681 | |||
682 | assert(strlen("-journal")==8); | ||
683 | assert(strcmp("-journal", &zPath[nName])==0); | ||
684 | |||
685 | pReal = pFsVfs->pFileList; | ||
686 | for(; pReal && strncmp(pReal->zName, zPath, nName); pReal=pReal->pNext); | ||
687 | if( pReal ){ | ||
688 | pF = pReal->pFile; | ||
689 | rc = pF->pMethods->xWrite(pF, "\0\0\0\0", 4, pReal->nBlob-BLOCKSIZE); | ||
690 | if( rc==SQLITE_OK ){ | ||
691 | pReal->nJournal = 0; | ||
692 | } | ||
693 | } | ||
694 | return rc; | ||
695 | } | ||
696 | |||
697 | /* | ||
698 | ** Test for access permissions. Return true if the requested permission | ||
699 | ** is available, or false otherwise. | ||
700 | */ | ||
701 | static int fsAccess(sqlite3_vfs *pVfs, const char *zPath, int flags){ | ||
702 | fs_vfs_t *pFsVfs = (fs_vfs_t *)pVfs; | ||
703 | fs_real_file *pReal; | ||
704 | int isJournal = 0; | ||
705 | int nName = strlen(zPath); | ||
706 | |||
707 | if( flags!=SQLITE_ACCESS_EXISTS ){ | ||
708 | sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; | ||
709 | return pParent->xAccess(pParent, zPath, flags); | ||
710 | } | ||
711 | |||
712 | assert(strlen("-journal")==8); | ||
713 | if( nName>8 && strcmp("-journal", &zPath[nName-8])==0 ){ | ||
714 | nName -= 8; | ||
715 | isJournal = 1; | ||
716 | } | ||
717 | |||
718 | pReal = pFsVfs->pFileList; | ||
719 | for(; pReal && strncmp(pReal->zName, zPath, nName); pReal=pReal->pNext); | ||
720 | if( !pReal ) return 0; | ||
721 | return ((!isJournal||pReal->nJournal>0)?1:0); | ||
722 | } | ||
723 | |||
724 | /* | ||
725 | ** Populate buffer zBufOut with a pathname suitable for use as a | ||
726 | ** temporary file. zBufOut is guaranteed to point to a buffer of | ||
727 | ** at least (FS_MAX_PATHNAME+1) bytes. | ||
728 | */ | ||
729 | static int fsGetTempname(sqlite3_vfs *pVfs, int nBufOut, char *zBufOut){ | ||
730 | sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; | ||
731 | return pParent->xGetTempname(pParent, nBufOut, zBufOut); | ||
732 | } | ||
733 | |||
734 | /* | ||
735 | ** Populate buffer zOut with the full canonical pathname corresponding | ||
736 | ** to the pathname in zPath. zOut is guaranteed to point to a buffer | ||
737 | ** of at least (FS_MAX_PATHNAME+1) bytes. | ||
738 | */ | ||
739 | static int fsFullPathname( | ||
740 | sqlite3_vfs *pVfs, /* Pointer to vfs object */ | ||
741 | const char *zPath, /* Possibly relative input path */ | ||
742 | int nOut, /* Size of output buffer in bytes */ | ||
743 | char *zOut /* Output buffer */ | ||
744 | ){ | ||
745 | sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; | ||
746 | return pParent->xFullPathname(pParent, zPath, nOut, zOut); | ||
747 | } | ||
748 | |||
749 | /* | ||
750 | ** Open the dynamic library located at zPath and return a handle. | ||
751 | */ | ||
752 | static void *fsDlOpen(sqlite3_vfs *pVfs, const char *zPath){ | ||
753 | sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; | ||
754 | return pParent->xDlOpen(pParent, zPath); | ||
755 | } | ||
756 | |||
757 | /* | ||
758 | ** Populate the buffer zErrMsg (size nByte bytes) with a human readable | ||
759 | ** utf-8 string describing the most recent error encountered associated | ||
760 | ** with dynamic libraries. | ||
761 | */ | ||
762 | static void fsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ | ||
763 | sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; | ||
764 | pParent->xDlError(pParent, nByte, zErrMsg); | ||
765 | } | ||
766 | |||
767 | /* | ||
768 | ** Return a pointer to the symbol zSymbol in the dynamic library pHandle. | ||
769 | */ | ||
770 | static void *fsDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){ | ||
771 | sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; | ||
772 | return pParent->xDlSym(pParent, pHandle, zSymbol); | ||
773 | } | ||
774 | |||
775 | /* | ||
776 | ** Close the dynamic library handle pHandle. | ||
777 | */ | ||
778 | static void fsDlClose(sqlite3_vfs *pVfs, void *pHandle){ | ||
779 | sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; | ||
780 | pParent->xDlClose(pParent, pHandle); | ||
781 | } | ||
782 | |||
783 | /* | ||
784 | ** Populate the buffer pointed to by zBufOut with nByte bytes of | ||
785 | ** random data. | ||
786 | */ | ||
787 | static int fsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ | ||
788 | sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; | ||
789 | return pParent->xRandomness(pParent, nByte, zBufOut); | ||
790 | } | ||
791 | |||
792 | /* | ||
793 | ** Sleep for nMicro microseconds. Return the number of microseconds | ||
794 | ** actually slept. | ||
795 | */ | ||
796 | static int fsSleep(sqlite3_vfs *pVfs, int nMicro){ | ||
797 | sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; | ||
798 | return pParent->xSleep(pParent, nMicro); | ||
799 | } | ||
800 | |||
801 | /* | ||
802 | ** Return the current time as a Julian Day number in *pTimeOut. | ||
803 | */ | ||
804 | static int fsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ | ||
805 | sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent; | ||
806 | return pParent->xCurrentTime(pParent, pTimeOut); | ||
807 | } | ||
808 | |||
809 | /* | ||
810 | ** This procedure registers the fs vfs with SQLite. If the argument is | ||
811 | ** true, the fs vfs becomes the new default vfs. It is the only publicly | ||
812 | ** available function in this file. | ||
813 | */ | ||
814 | int fs_register(){ | ||
815 | if( fs_vfs.pParent ) return SQLITE_OK; | ||
816 | fs_vfs.pParent = sqlite3_vfs_find(0); | ||
817 | fs_vfs.base.mxPathname = fs_vfs.pParent->mxPathname; | ||
818 | fs_vfs.base.szOsFile = MAX(sizeof(tmp_file), sizeof(fs_file)); | ||
819 | return sqlite3_vfs_register(&fs_vfs.base, 0); | ||
820 | } | ||
821 | |||
822 | #ifdef SQLITE_TEST | ||
823 | int SqlitetestOnefile_Init() {return fs_register();} | ||
824 | #endif | ||
825 | |||