Line | Count | Source (jump to first uncovered line) |
1 | | /* Derived from https://www.sqlite.org/src/doc/tip/ext/misc/memvfs.c */ |
2 | | /* |
3 | | ** 2016-09-07 |
4 | | ** |
5 | | ** The author disclaims copyright to this source code. In place of |
6 | | ** a legal notice, here is a blessing: |
7 | | ** |
8 | | ** May you do good and not evil. |
9 | | ** May you find forgiveness for yourself and forgive others. |
10 | | ** May you share freely, never taking more than you give. |
11 | | ** |
12 | | ****************************************************************************** |
13 | | ** |
14 | | ** This is an in-memory VFS implementation. The application supplies |
15 | | ** a chunk of memory to hold the database file. |
16 | | ** |
17 | | ** Because there is place to store a rollback or wal journal, the database |
18 | | ** must use one of journal_mode=MEMORY or journal_mode=NONE. |
19 | | ** |
20 | | ** USAGE: |
21 | | ** |
22 | | ** sqlite3_open_v2("file:/whatever?ptr=0xf05538&sz=14336&max=65536", &db, |
23 | | ** SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI, |
24 | | ** "memvfs"); |
25 | | ** |
26 | | ** These are the query parameters: |
27 | | ** |
28 | | ** ptr= The address of the memory buffer that holds the database. |
29 | | ** |
30 | | ** sz= The current size the database file |
31 | | ** |
32 | | ** maxsz= The maximum size of the database. In other words, the |
33 | | ** amount of space allocated for the ptr= buffer. |
34 | | ** |
35 | | ** The ptr= and sz= query parameters are required. If maxsz= is omitted, |
36 | | ** then it defaults to the sz= value. Parameter values can be in either |
37 | | ** decimal or hexadecimal. The filename in the URI is ignored. |
38 | | */ |
39 | | #include <sqlite3.h> |
40 | | |
41 | | #include <assert.h> |
42 | | #include <stdint.h> |
43 | | #include <string.h> |
44 | | |
45 | | #include "memvfs.h" |
46 | | |
47 | | #ifdef __GNUC__ |
48 | | #pragma GCC diagnostic push |
49 | | #pragma GCC diagnostic ignored "-Wunused-parameter" |
50 | | #pragma GCC diagnostic ignored "-Wmissing-field-initializers" |
51 | | #endif |
52 | | |
53 | | #ifdef _MSC_VER |
54 | | #pragma warning(push) |
55 | | // Ignore unreferenced formal parameter |
56 | | #pragma warning(disable : 4100) |
57 | | #endif |
58 | | |
59 | | /* |
60 | | ** Forward declaration of objects used by this utility |
61 | | */ |
62 | | typedef struct sqlite3_vfs MemVfs; |
63 | | typedef struct MemFile MemFile; |
64 | | |
65 | | typedef struct MemVfsAppData { |
66 | | const unsigned char *buffer; |
67 | | size_t bufferSize; |
68 | | sqlite3_vfs *pBaseVFS; |
69 | | } MemVfsAppData; |
70 | | |
71 | | /* Access to a lower-level VFS that (might) implement dynamic loading, |
72 | | ** access to randomness, etc. |
73 | | */ |
74 | 9.60k | #define ORIGVFS(p) (((MemVfsAppData *)((p)->pAppData))->pBaseVFS) |
75 | | |
76 | | /* An open file */ |
77 | | struct MemFile { |
78 | | sqlite3_file base; /* IO methods */ |
79 | | sqlite3_int64 sz; /* Size of the file */ |
80 | | sqlite3_int64 szMax; /* Space allocated to aData */ |
81 | | const unsigned char *aData; /* content of the file */ |
82 | | }; |
83 | | |
84 | | /* |
85 | | ** Methods for MemFile |
86 | | */ |
87 | | static int memClose(sqlite3_file *); |
88 | | static int memRead(sqlite3_file *, void *, int iAmt, sqlite3_int64 iOfst); |
89 | | static int memWrite(sqlite3_file *, const void *, int iAmt, |
90 | | sqlite3_int64 iOfst); |
91 | | static int memTruncate(sqlite3_file *, sqlite3_int64 size); |
92 | | static int memSync(sqlite3_file *, int flags); |
93 | | static int memFileSize(sqlite3_file *, sqlite3_int64 *pSize); |
94 | | static int memLock(sqlite3_file *, int); |
95 | | static int memUnlock(sqlite3_file *, int); |
96 | | static int memCheckReservedLock(sqlite3_file *, int *pResOut); |
97 | | static int memFileControl(sqlite3_file *, int op, void *pArg); |
98 | | static int memSectorSize(sqlite3_file *); |
99 | | static int memDeviceCharacteristics(sqlite3_file *); |
100 | | static int memShmMap(sqlite3_file *, int iPg, int pgsz, int, void volatile **); |
101 | | static int memShmLock(sqlite3_file *, int offset, int n, int flags); |
102 | | static void memShmBarrier(sqlite3_file *); |
103 | | static int memShmUnmap(sqlite3_file *, int deleteFlag); |
104 | | static int memFetch(sqlite3_file *, sqlite3_int64 iOfst, int iAmt, void **pp); |
105 | | static int memUnfetch(sqlite3_file *, sqlite3_int64 iOfst, void *p); |
106 | | |
107 | | /* |
108 | | ** Methods for MemVfs |
109 | | */ |
110 | | static int memOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int *); |
111 | | static int memDelete(sqlite3_vfs *, const char *zName, int syncDir); |
112 | | static int memAccess(sqlite3_vfs *, const char *zName, int flags, int *); |
113 | | static int memFullPathname(sqlite3_vfs *, const char *zName, int, char *zOut); |
114 | | static void *memDlOpen(sqlite3_vfs *, const char *zFilename); |
115 | | static void memDlError(sqlite3_vfs *, int nByte, char *zErrMsg); |
116 | | static void (*memDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void); |
117 | | static void memDlClose(sqlite3_vfs *, void *); |
118 | | static int memRandomness(sqlite3_vfs *, int nByte, char *zOut); |
119 | | static int memSleep(sqlite3_vfs *, int microseconds); |
120 | | static int memCurrentTime(sqlite3_vfs *, double *); |
121 | | static int memGetLastError(sqlite3_vfs *, int, char *); |
122 | | static int memCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64 *); |
123 | | |
124 | | static sqlite3_vfs mem_vfs = { |
125 | | 2, /* iVersion */ |
126 | | 0, /* szOsFile (set when registered) */ |
127 | | 1024, /* mxPathname */ |
128 | | 0, /* pNext */ |
129 | | "memvfs", /* zName */ |
130 | | 0, /* pAppData (set when registered) */ |
131 | | memOpen, /* xOpen */ |
132 | | memDelete, /* xDelete */ |
133 | | memAccess, /* xAccess */ |
134 | | memFullPathname, /* xFullPathname */ |
135 | | memDlOpen, /* xDlOpen */ |
136 | | memDlError, /* xDlError */ |
137 | | memDlSym, /* xDlSym */ |
138 | | memDlClose, /* xDlClose */ |
139 | | memRandomness, /* xRandomness */ |
140 | | memSleep, /* xSleep */ |
141 | | memCurrentTime, /* xCurrentTime */ |
142 | | memGetLastError, /* xGetLastError */ |
143 | | memCurrentTimeInt64 /* xCurrentTimeInt64 */ |
144 | | }; |
145 | | |
146 | | static const sqlite3_io_methods mem_io_methods = { |
147 | | 3, /* iVersion */ |
148 | | memClose, /* xClose */ |
149 | | memRead, /* xRead */ |
150 | | memWrite, /* xWrite */ |
151 | | memTruncate, /* xTruncate */ |
152 | | memSync, /* xSync */ |
153 | | memFileSize, /* xFileSize */ |
154 | | memLock, /* xLock */ |
155 | | memUnlock, /* xUnlock */ |
156 | | memCheckReservedLock, /* xCheckReservedLock */ |
157 | | memFileControl, /* xFileControl */ |
158 | | memSectorSize, /* xSectorSize */ |
159 | | memDeviceCharacteristics, /* xDeviceCharacteristics */ |
160 | | memShmMap, /* xShmMap */ |
161 | | memShmLock, /* xShmLock */ |
162 | | memShmBarrier, /* xShmBarrier */ |
163 | | memShmUnmap, /* xShmUnmap */ |
164 | | memFetch, /* xFetch */ |
165 | | memUnfetch /* xUnfetch */ |
166 | | }; |
167 | | |
168 | | /* |
169 | | ** Close an mem-file. |
170 | | ** |
171 | | ** The pData pointer is owned by the application, so there is nothing |
172 | | ** to free. |
173 | | */ |
174 | 0 | static int memClose(sqlite3_file *pFile) { return SQLITE_OK; } |
175 | | |
176 | | /* |
177 | | ** Read data from an mem-file. |
178 | | */ |
179 | | static int memRead(sqlite3_file *pFile, void *zBuf, int iAmt, |
180 | 6.39M | sqlite_int64 iOfst) { |
181 | 6.39M | MemFile *p = (MemFile *)pFile; |
182 | 6.39M | memcpy(zBuf, p->aData + iOfst, iAmt); |
183 | 6.39M | return SQLITE_OK; |
184 | 6.39M | } |
185 | | |
186 | | /* |
187 | | ** Write data to an mem-file. |
188 | | */ |
189 | | static int memWrite(sqlite3_file *pFile, const void *z, int iAmt, |
190 | 0 | sqlite_int64 iOfst) { |
191 | 0 | return SQLITE_READONLY; |
192 | 0 | } |
193 | | |
194 | | /* |
195 | | ** Truncate an mem-file. |
196 | | */ |
197 | 0 | static int memTruncate(sqlite3_file *pFile, sqlite_int64 size) { |
198 | 0 | return SQLITE_READONLY; |
199 | 0 | } |
200 | | |
201 | | /* |
202 | | ** Sync an mem-file. |
203 | | */ |
204 | 0 | static int memSync(sqlite3_file *pFile, int flags) { return SQLITE_OK; } |
205 | | |
206 | | /* |
207 | | ** Return the current file-size of an mem-file. |
208 | | */ |
209 | 1 | static int memFileSize(sqlite3_file *pFile, sqlite_int64 *pSize) { |
210 | 1 | MemFile *p = (MemFile *)pFile; |
211 | 1 | *pSize = p->sz; |
212 | 1 | return SQLITE_OK; |
213 | 1 | } |
214 | | |
215 | | /* |
216 | | ** Lock an mem-file. |
217 | | */ |
218 | 0 | static int memLock(sqlite3_file *pFile, int eLock) { return SQLITE_OK; } |
219 | | |
220 | | /* |
221 | | ** Unlock an mem-file. |
222 | | */ |
223 | 0 | static int memUnlock(sqlite3_file *pFile, int eLock) { return SQLITE_OK; } |
224 | | |
225 | | /* |
226 | | ** Check if another file-handle holds a RESERVED lock on an mem-file. |
227 | | */ |
228 | 0 | static int memCheckReservedLock(sqlite3_file *pFile, int *pResOut) { |
229 | 0 | *pResOut = 0; |
230 | 0 | return SQLITE_OK; |
231 | 0 | } |
232 | | |
233 | | /* |
234 | | ** File control method. For custom operations on an mem-file. |
235 | | */ |
236 | 5 | static int memFileControl(sqlite3_file *pFile, int op, void *pArg) { |
237 | 5 | MemFile *p = (MemFile *)pFile; |
238 | 5 | int rc = SQLITE_NOTFOUND; |
239 | 5 | if (op == SQLITE_FCNTL_VFSNAME) { |
240 | 0 | *(char **)pArg = sqlite3_mprintf("mem(%p,%lld)", p->aData, p->sz); |
241 | 0 | rc = SQLITE_OK; |
242 | 0 | } |
243 | 5 | return rc; |
244 | 5 | } |
245 | | |
246 | | /* |
247 | | ** Return the sector-size in bytes for an mem-file. |
248 | | */ |
249 | 0 | static int memSectorSize(sqlite3_file *pFile) { return 1024; } |
250 | | |
251 | | /* |
252 | | ** Return the device characteristic flags supported by an mem-file. |
253 | | */ |
254 | 2 | static int memDeviceCharacteristics(sqlite3_file *pFile) { |
255 | 2 | return SQLITE_IOCAP_ATOMIC | SQLITE_IOCAP_POWERSAFE_OVERWRITE | |
256 | 2 | SQLITE_IOCAP_SAFE_APPEND | SQLITE_IOCAP_SEQUENTIAL; |
257 | 2 | } |
258 | | |
259 | | /* Create a shared memory file mapping */ |
260 | | static int memShmMap(sqlite3_file *pFile, int iPg, int pgsz, int bExtend, |
261 | 0 | void volatile **pp) { |
262 | 0 | return SQLITE_IOERR_SHMMAP; |
263 | 0 | } |
264 | | |
265 | | /* Perform locking on a shared-memory segment */ |
266 | 0 | static int memShmLock(sqlite3_file *pFile, int offset, int n, int flags) { |
267 | 0 | return SQLITE_IOERR_SHMLOCK; |
268 | 0 | } |
269 | | |
270 | | /* Memory barrier operation on shared memory */ |
271 | 0 | static void memShmBarrier(sqlite3_file *pFile) { return; } |
272 | | |
273 | | /* Unmap a shared memory segment */ |
274 | 0 | static int memShmUnmap(sqlite3_file *pFile, int deleteFlag) { |
275 | 0 | return SQLITE_OK; |
276 | 0 | } |
277 | | |
278 | | /* Fetch a page of a memory-mapped file */ |
279 | | static int memFetch(sqlite3_file *pFile, sqlite3_int64 iOfst, int iAmt, |
280 | 0 | void **pp) { |
281 | 0 | MemFile *p = (MemFile *)pFile; |
282 | 0 | *pp = (void *)(p->aData + iOfst); |
283 | 0 | return SQLITE_OK; |
284 | 0 | } |
285 | | |
286 | | /* Release a memory-mapped page */ |
287 | 0 | static int memUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage) { |
288 | 0 | return SQLITE_OK; |
289 | 0 | } |
290 | | |
291 | | /* |
292 | | ** Open an mem file handle. |
293 | | */ |
294 | | static int memOpen(sqlite3_vfs *pVfs, const char *zName, sqlite3_file *pFile, |
295 | 4.80k | int flags, int *pOutFlags) { |
296 | 4.80k | MemFile *p = (MemFile *)pFile; |
297 | 4.80k | MemVfsAppData *appData = (MemVfsAppData *)(pVfs->pAppData); |
298 | 4.80k | memset(p, 0, sizeof(*p)); |
299 | 4.80k | if ((flags & SQLITE_OPEN_MAIN_DB) == 0) { |
300 | | /* Modification w.r.t upstream: instead of returning SQLITE_CANTOPEN, |
301 | | * delegate to origin VFS. Typically for temporary file creation. |
302 | | */ |
303 | 4.80k | return ORIGVFS(pVfs)->xOpen(ORIGVFS(pVfs), zName, pFile, flags, |
304 | 4.80k | pOutFlags); |
305 | 4.80k | } |
306 | 1 | if ((uintptr_t)(appData->buffer) != |
307 | 1 | (uintptr_t)sqlite3_uri_int64(zName, "ptr", 0)) { |
308 | 0 | return SQLITE_CANTOPEN; |
309 | 0 | } |
310 | 1 | p->aData = appData->buffer; |
311 | 1 | p->sz = sqlite3_uri_int64(zName, "sz", 0); |
312 | 1 | if (p->sz < 0 || (size_t)p->sz != appData->bufferSize) |
313 | 0 | return SQLITE_CANTOPEN; |
314 | 1 | p->szMax = sqlite3_uri_int64(zName, "max", p->sz); |
315 | 1 | if (p->szMax < p->sz) |
316 | 0 | return SQLITE_CANTOPEN; |
317 | 1 | pFile->pMethods = &mem_io_methods; |
318 | 1 | return SQLITE_OK; |
319 | 1 | } |
320 | | |
321 | | /* |
322 | | ** Delete the file located at zPath. If the dirSync argument is true, |
323 | | ** ensure the file-system modifications are synced to disk before |
324 | | ** returning. |
325 | | */ |
326 | 0 | static int memDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync) { |
327 | 0 | return SQLITE_IOERR_DELETE; |
328 | 0 | } |
329 | | |
330 | | /* |
331 | | ** Test for access permissions. Return true if the requested permission |
332 | | ** is available, or false otherwise. |
333 | | */ |
334 | | static int memAccess(sqlite3_vfs *pVfs, const char *zPath, int flags, |
335 | 0 | int *pResOut) { |
336 | 0 | *pResOut = 0; |
337 | 0 | return SQLITE_OK; |
338 | 0 | } |
339 | | |
340 | | /* |
341 | | ** Populate buffer zOut with the full canonical pathname corresponding |
342 | | ** to the pathname in zPath. zOut is guaranteed to point to a buffer |
343 | | ** of at least (INST_MAX_PATHNAME+1) bytes. |
344 | | */ |
345 | | static int memFullPathname(sqlite3_vfs *pVfs, const char *zPath, int nOut, |
346 | 1 | char *zOut) { |
347 | 1 | sqlite3_snprintf(nOut, zOut, "%s", zPath); |
348 | 1 | return SQLITE_OK; |
349 | 1 | } |
350 | | |
351 | | /* |
352 | | ** Open the dynamic library located at zPath and return a handle. |
353 | | */ |
354 | 0 | static void *memDlOpen(sqlite3_vfs *pVfs, const char *zPath) { |
355 | 0 | return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath); |
356 | 0 | } |
357 | | |
358 | | /* |
359 | | ** Populate the buffer zErrMsg (size nByte bytes) with a human readable |
360 | | ** utf-8 string describing the most recent error encountered associated |
361 | | ** with dynamic libraries. |
362 | | */ |
363 | 0 | static void memDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg) { |
364 | 0 | ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg); |
365 | 0 | } |
366 | | |
367 | | /* |
368 | | ** Return a pointer to the symbol zSymbol in the dynamic library pHandle. |
369 | | */ |
370 | 0 | static void (*memDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void) { |
371 | 0 | return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym); |
372 | 0 | } |
373 | | |
374 | | /* |
375 | | ** Close the dynamic library handle pHandle. |
376 | | */ |
377 | 0 | static void memDlClose(sqlite3_vfs *pVfs, void *pHandle) { |
378 | 0 | ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle); |
379 | 0 | } |
380 | | |
381 | | /* |
382 | | ** Populate the buffer pointed to by zBufOut with nByte bytes of |
383 | | ** random data. |
384 | | */ |
385 | 0 | static int memRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut) { |
386 | 0 | return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut); |
387 | 0 | } |
388 | | |
389 | | /* |
390 | | ** Sleep for nMicro microseconds. Return the number of microseconds |
391 | | ** actually slept. |
392 | | */ |
393 | 0 | static int memSleep(sqlite3_vfs *pVfs, int nMicro) { |
394 | 0 | return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro); |
395 | 0 | } |
396 | | |
397 | | /* |
398 | | ** Return the current time as a Julian Day number in *pTimeOut. |
399 | | */ |
400 | 0 | static int memCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut) { |
401 | 0 | return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut); |
402 | 0 | } |
403 | | |
404 | 0 | static int memGetLastError(sqlite3_vfs *pVfs, int a, char *b) { |
405 | 0 | return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b); |
406 | 0 | } |
407 | 0 | static int memCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p) { |
408 | 0 | return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p); |
409 | 0 | } |
410 | | |
411 | | /* |
412 | | * Register the new VFS. |
413 | | */ |
414 | | int pj_sqlite3_memvfs_init(sqlite3_vfs *vfs, const char *vfs_name, |
415 | 1 | const void *buffer, size_t bufferSize) { |
416 | 1 | memcpy(vfs, &mem_vfs, sizeof(mem_vfs)); |
417 | 1 | vfs->zName = vfs_name; |
418 | 1 | sqlite3_vfs *defaultVFS = sqlite3_vfs_find(NULL); |
419 | 1 | if (!defaultVFS) |
420 | 0 | return SQLITE_ERROR; |
421 | 1 | MemVfsAppData *appData = |
422 | 1 | (MemVfsAppData *)sqlite3_malloc(sizeof(MemVfsAppData)); |
423 | 1 | appData->buffer = buffer; |
424 | 1 | appData->bufferSize = bufferSize; |
425 | 1 | appData->pBaseVFS = defaultVFS; |
426 | 1 | vfs->pAppData = appData; |
427 | 1 | vfs->szOsFile = sizeof(MemFile); |
428 | | /* Modification w.r.t upstream: as we might delegate file opening |
429 | | * to default VFS for temporary files, we need to make sure szOsFile is |
430 | | * the maximum of our own need and of the default VFS. |
431 | | */ |
432 | 1 | if (vfs->szOsFile < defaultVFS->szOsFile) |
433 | 1 | vfs->szOsFile = defaultVFS->szOsFile; |
434 | 1 | return sqlite3_vfs_register(vfs, 0); |
435 | 1 | } |
436 | | |
437 | 0 | void pj_sqlite3_memvfs_deallocate_user_data(sqlite3_vfs *vfs) { |
438 | 0 | sqlite3_free(vfs->pAppData); |
439 | 0 | vfs->pAppData = NULL; |
440 | 0 | } |
441 | | |
442 | | #ifdef _MSC_VER |
443 | | #pragma warning(pop) |
444 | | #endif |
445 | | |
446 | | #ifdef __GNUC__ |
447 | | #pragma GCC diagnostic pop |
448 | | #endif |