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