Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: 5e0ea49f1635e116aed1584a2bf63c6420655a35 [file] [log] [blame]
drh59ece7e2022-09-07 17:29:221/*
2** 2022-09-06
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** This file contains an experimental VFS layer that operates on a
14** Key/Value storage engine where both keys and values must be pure
15** text.
16*/
drh7585f492022-09-10 18:20:5917#include <sqliteInt.h>
drh20a9ed12022-09-17 18:29:4918#if SQLITE_OS_KV || (SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL))
drhe3485ee2022-09-08 16:27:5019
20/*****************************************************************************
21** Debugging logic
22*/
drhf7377d52022-09-09 14:22:4123
drh7585f492022-09-10 18:20:5924/* SQLITE_KV_TRACE() is used for tracing calls to kvstorage routines. */
drh126976c2022-09-09 11:41:5425#if 0
stephand35b5582022-10-09 13:19:2726#define SQLITE_KV_TRACE(X) printf X
drhe3485ee2022-09-08 16:27:5027#else
drh7585f492022-09-10 18:20:5928#define SQLITE_KV_TRACE(X)
drhe3485ee2022-09-08 16:27:5029#endif
drhf7377d52022-09-09 14:22:4130
drh7585f492022-09-10 18:20:5931/* SQLITE_KV_LOG() is used for tracing calls to the VFS interface */
drh126976c2022-09-09 11:41:5432#if 0
stephand35b5582022-10-09 13:19:2733#define SQLITE_KV_LOG(X) printf X
drh126976c2022-09-09 11:41:5434#else
drh7585f492022-09-10 18:20:5935#define SQLITE_KV_LOG(X)
drh126976c2022-09-09 11:41:5436#endif
drh59ece7e2022-09-07 17:29:2237
38
drh59ece7e2022-09-07 17:29:2239/*
drh25f62502022-09-09 16:16:3340** Forward declaration of objects used by this VFS implementation
drh59ece7e2022-09-07 17:29:2241*/
drh59ece7e2022-09-07 17:29:2242typedef struct KVVfsFile KVVfsFile;
43
drhcb941322022-09-08 15:48:0144/* A single open file. There are only two files represented by this
45** VFS - the database and the rollback journal.
46*/
drh59ece7e2022-09-07 17:29:2247struct KVVfsFile {
48 sqlite3_file base; /* IO methods */
drh25f62502022-09-09 16:16:3349 const char *zClass; /* Storage class */
drh59ece7e2022-09-07 17:29:2250 int isJournal; /* True if this is a journal file */
drhcb941322022-09-08 15:48:0151 unsigned int nJrnl; /* Space allocated for aJrnl[] */
drh59ece7e2022-09-07 17:29:2252 char *aJrnl; /* Journal content */
drhcb941322022-09-08 15:48:0153 int szPage; /* Last known page size */
54 sqlite3_int64 szDb; /* Database file size. -1 means unknown */
stephanfed255d2022-12-03 11:51:2955 char *aData; /* Buffer to hold page data */
drh59ece7e2022-09-07 17:29:2256};
stephanfed255d2022-12-03 11:51:2957#define SQLITE_KVOS_SZ 133073
drh59ece7e2022-09-07 17:29:2258
59/*
60** Methods for KVVfsFile
61*/
62static int kvvfsClose(sqlite3_file*);
drhf7377d52022-09-09 14:22:4163static int kvvfsReadDb(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
64static int kvvfsReadJrnl(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
65static int kvvfsWriteDb(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
66static int kvvfsWriteJrnl(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
67static int kvvfsTruncateDb(sqlite3_file*, sqlite3_int64 size);
68static int kvvfsTruncateJrnl(sqlite3_file*, sqlite3_int64 size);
69static int kvvfsSyncDb(sqlite3_file*, int flags);
70static int kvvfsSyncJrnl(sqlite3_file*, int flags);
71static int kvvfsFileSizeDb(sqlite3_file*, sqlite3_int64 *pSize);
72static int kvvfsFileSizeJrnl(sqlite3_file*, sqlite3_int64 *pSize);
drh59ece7e2022-09-07 17:29:2273static int kvvfsLock(sqlite3_file*, int);
74static int kvvfsUnlock(sqlite3_file*, int);
75static int kvvfsCheckReservedLock(sqlite3_file*, int *pResOut);
drh84e50762022-09-16 11:37:0176static int kvvfsFileControlDb(sqlite3_file*, int op, void *pArg);
77static int kvvfsFileControlJrnl(sqlite3_file*, int op, void *pArg);
drh59ece7e2022-09-07 17:29:2278static int kvvfsSectorSize(sqlite3_file*);
79static int kvvfsDeviceCharacteristics(sqlite3_file*);
80
81/*
drh25f62502022-09-09 16:16:3382** Methods for sqlite3_vfs
drh59ece7e2022-09-07 17:29:2283*/
84static int kvvfsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
85static int kvvfsDelete(sqlite3_vfs*, const char *zName, int syncDir);
86static int kvvfsAccess(sqlite3_vfs*, const char *zName, int flags, int *);
87static int kvvfsFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
88static void *kvvfsDlOpen(sqlite3_vfs*, const char *zFilename);
drh59ece7e2022-09-07 17:29:2289static int kvvfsRandomness(sqlite3_vfs*, int nByte, char *zOut);
90static int kvvfsSleep(sqlite3_vfs*, int microseconds);
91static int kvvfsCurrentTime(sqlite3_vfs*, double*);
drh59ece7e2022-09-07 17:29:2292static int kvvfsCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
93
drh20a9ed12022-09-17 18:29:4994static sqlite3_vfs sqlite3OsKvvfsObject = {
drh25f62502022-09-09 16:16:3395 1, /* iVersion */
96 sizeof(KVVfsFile), /* szOsFile */
97 1024, /* mxPathname */
98 0, /* pNext */
99 "kvvfs", /* zName */
100 0, /* pAppData */
101 kvvfsOpen, /* xOpen */
102 kvvfsDelete, /* xDelete */
103 kvvfsAccess, /* xAccess */
104 kvvfsFullPathname, /* xFullPathname */
105 kvvfsDlOpen, /* xDlOpen */
106 0, /* xDlError */
107 0, /* xDlSym */
108 0, /* xDlClose */
109 kvvfsRandomness, /* xRandomness */
110 kvvfsSleep, /* xSleep */
111 kvvfsCurrentTime, /* xCurrentTime */
112 0, /* xGetLastError */
113 kvvfsCurrentTimeInt64 /* xCurrentTimeInt64 */
drh59ece7e2022-09-07 17:29:22114};
115
drhf7377d52022-09-09 14:22:41116/* Methods for sqlite3_file objects referencing a database file
117*/
118static sqlite3_io_methods kvvfs_db_io_methods = {
drh59ece7e2022-09-07 17:29:22119 1, /* iVersion */
120 kvvfsClose, /* xClose */
drhf7377d52022-09-09 14:22:41121 kvvfsReadDb, /* xRead */
122 kvvfsWriteDb, /* xWrite */
123 kvvfsTruncateDb, /* xTruncate */
124 kvvfsSyncDb, /* xSync */
125 kvvfsFileSizeDb, /* xFileSize */
126 kvvfsLock, /* xLock */
127 kvvfsUnlock, /* xUnlock */
128 kvvfsCheckReservedLock, /* xCheckReservedLock */
drh84e50762022-09-16 11:37:01129 kvvfsFileControlDb, /* xFileControl */
drhf7377d52022-09-09 14:22:41130 kvvfsSectorSize, /* xSectorSize */
131 kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */
132 0, /* xShmMap */
133 0, /* xShmLock */
134 0, /* xShmBarrier */
135 0, /* xShmUnmap */
136 0, /* xFetch */
137 0 /* xUnfetch */
138};
139
140/* Methods for sqlite3_file objects referencing a rollback journal
141*/
142static sqlite3_io_methods kvvfs_jrnl_io_methods = {
143 1, /* iVersion */
144 kvvfsClose, /* xClose */
145 kvvfsReadJrnl, /* xRead */
146 kvvfsWriteJrnl, /* xWrite */
147 kvvfsTruncateJrnl, /* xTruncate */
148 kvvfsSyncJrnl, /* xSync */
149 kvvfsFileSizeJrnl, /* xFileSize */
drh59ece7e2022-09-07 17:29:22150 kvvfsLock, /* xLock */
151 kvvfsUnlock, /* xUnlock */
152 kvvfsCheckReservedLock, /* xCheckReservedLock */
drh84e50762022-09-16 11:37:01153 kvvfsFileControlJrnl, /* xFileControl */
drh59ece7e2022-09-07 17:29:22154 kvvfsSectorSize, /* xSectorSize */
drhe3485ee2022-09-08 16:27:50155 kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */
drh59ece7e2022-09-07 17:29:22156 0, /* xShmMap */
157 0, /* xShmLock */
158 0, /* xShmBarrier */
159 0, /* xShmUnmap */
160 0, /* xFetch */
161 0 /* xUnfetch */
162};
163
164/****** Storage subsystem **************************************************/
drh7585f492022-09-10 18:20:59165#include <sys/types.h>
166#include <sys/stat.h>
167#include <unistd.h>
168
169/* Forward declarations for the low-level storage engine
170*/
stephand35b5582022-10-09 13:19:27171static int kvstorageWrite(const char*, const char *zKey, const char *zData);
172static int kvstorageDelete(const char*, const char *zKey);
173static int kvstorageRead(const char*, const char *zKey, char *zBuf, int nBuf);
drhc6c9c6a2022-09-10 18:38:21174#define KVSTORAGE_KEY_SZ 32
drh59ece7e2022-09-07 17:29:22175
176/* Expand the key name with an appropriate prefix and put the result
drhc6c9c6a2022-09-10 18:38:21177** zKeyOut[]. The zKeyOut[] buffer is assumed to hold at least
178** KVSTORAGE_KEY_SZ bytes.
drh59ece7e2022-09-07 17:29:22179*/
drh25f62502022-09-09 16:16:33180static void kvstorageMakeKey(
181 const char *zClass,
182 const char *zKeyIn,
183 char *zKeyOut
184){
drhc6c9c6a2022-09-10 18:38:21185 sqlite3_snprintf(KVSTORAGE_KEY_SZ, zKeyOut, "kvvfs-%s-%s", zClass, zKeyIn);
drh59ece7e2022-09-07 17:29:22186}
187
drhc6c9c6a2022-09-10 18:38:21188/* Write content into a key. zClass is the particular namespace of the
189** underlying key/value store to use - either "local" or "session".
190**
191** Both zKey and zData are zero-terminated pure text strings.
drh59ece7e2022-09-07 17:29:22192**
193** Return the number of errors.
194*/
195static int kvstorageWrite(
drh25f62502022-09-09 16:16:33196 const char *zClass,
drh59ece7e2022-09-07 17:29:22197 const char *zKey,
198 const char *zData
199){
200 FILE *fd;
drh25f62502022-09-09 16:16:33201 char zXKey[KVSTORAGE_KEY_SZ];
202 kvstorageMakeKey(zClass, zKey, zXKey);
203 fd = fopen(zXKey, "wb");
drh59ece7e2022-09-07 17:29:22204 if( fd ){
drh7585f492022-09-10 18:20:59205 SQLITE_KV_TRACE(("KVVFS-WRITE %-15s (%d) %.50s%s\n", zXKey,
drhf7377d52022-09-09 14:22:41206 (int)strlen(zData), zData,
207 strlen(zData)>50 ? "..." : ""));
drh59ece7e2022-09-07 17:29:22208 fputs(zData, fd);
209 fclose(fd);
drhe3485ee2022-09-08 16:27:50210 return 0;
211 }else{
212 return 1;
drh59ece7e2022-09-07 17:29:22213 }
drh59ece7e2022-09-07 17:29:22214}
215
drhc6c9c6a2022-09-10 18:38:21216/* Delete a key (with its corresponding data) from the key/value
217** namespace given by zClass. If the key does not previously exist,
218** this routine is a no-op.
drh59ece7e2022-09-07 17:29:22219*/
drh25f62502022-09-09 16:16:33220static int kvstorageDelete(const char *zClass, const char *zKey){
221 char zXKey[KVSTORAGE_KEY_SZ];
222 kvstorageMakeKey(zClass, zKey, zXKey);
223 unlink(zXKey);
drh7585f492022-09-10 18:20:59224 SQLITE_KV_TRACE(("KVVFS-DELETE %-15s\n", zXKey));
drh59ece7e2022-09-07 17:29:22225 return 0;
226}
227
drhc6c9c6a2022-09-10 18:38:21228/* Read the value associated with a zKey from the key/value namespace given
229** by zClass and put the text data associated with that key in the first
drh59ece7e2022-09-07 17:29:22230** nBuf bytes of zBuf[]. The value might be truncated if zBuf is not large
drhc6c9c6a2022-09-10 18:38:21231** enough to hold it all. The value put into zBuf must always be zero
232** terminated, even if it gets truncated because nBuf is not large enough.
drh59ece7e2022-09-07 17:29:22233**
234** Return the total number of bytes in the data, without truncation, and
235** not counting the final zero terminator. Return -1 if the key does
236** not exist.
237**
drhc6c9c6a2022-09-10 18:38:21238** If nBuf<=0 then this routine simply returns the size of the data without
drh59ece7e2022-09-07 17:29:22239** actually reading it.
240*/
241static int kvstorageRead(
drh25f62502022-09-09 16:16:33242 const char *zClass,
drh59ece7e2022-09-07 17:29:22243 const char *zKey,
244 char *zBuf,
245 int nBuf
246){
247 FILE *fd;
248 struct stat buf;
drh25f62502022-09-09 16:16:33249 char zXKey[KVSTORAGE_KEY_SZ];
250 kvstorageMakeKey(zClass, zKey, zXKey);
251 if( access(zXKey, R_OK)!=0
252 || stat(zXKey, &buf)!=0
drh59ece7e2022-09-07 17:29:22253 || !S_ISREG(buf.st_mode)
254 ){
drh7585f492022-09-10 18:20:59255 SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey));
drh59ece7e2022-09-07 17:29:22256 return -1;
257 }
drhc6c9c6a2022-09-10 18:38:21258 if( nBuf<=0 ){
drh59ece7e2022-09-07 17:29:22259 return (int)buf.st_size;
260 }else if( nBuf==1 ){
261 zBuf[0] = 0;
drh7585f492022-09-10 18:20:59262 SQLITE_KV_TRACE(("KVVFS-READ %-15s (%d)\n", zXKey,
drhe3485ee2022-09-08 16:27:50263 (int)buf.st_size));
drh59ece7e2022-09-07 17:29:22264 return (int)buf.st_size;
265 }
drh25f62502022-09-09 16:16:33266 if( nBuf > buf.st_size + 1 ){
drh59ece7e2022-09-07 17:29:22267 nBuf = buf.st_size + 1;
268 }
drh25f62502022-09-09 16:16:33269 fd = fopen(zXKey, "rb");
drhe3485ee2022-09-08 16:27:50270 if( fd==0 ){
drh7585f492022-09-10 18:20:59271 SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey));
drhe3485ee2022-09-08 16:27:50272 return -1;
273 }else{
drh126976c2022-09-09 11:41:54274 sqlite3_int64 n = fread(zBuf, 1, nBuf-1, fd);
drhe3485ee2022-09-08 16:27:50275 fclose(fd);
drh126976c2022-09-09 11:41:54276 zBuf[n] = 0;
drh7585f492022-09-10 18:20:59277 SQLITE_KV_TRACE(("KVVFS-READ %-15s (%lld) %.50s%s\n", zXKey,
drhf7377d52022-09-09 14:22:41278 n, zBuf, n>50 ? "..." : ""));
drh126976c2022-09-09 11:41:54279 return (int)n;
drhe3485ee2022-09-08 16:27:50280 }
drh59ece7e2022-09-07 17:29:22281}
stephand35b5582022-10-09 13:19:27282
283/*
284** An internal level of indirection which enables us to replace the
285** kvvfs i/o methods with JavaScript implementations in WASM builds.
286** Maintenance reminder: if this struct changes in any way, the JSON
287** rendering of its structure must be updated in
288** sqlite3_wasm_enum_json(). There are no binary compatibility
289** concerns, so it does not need an iVersion member. This file is
290** necessarily always compiled together with sqlite3_wasm_enum_json(),
291** and JS code dynamically creates the mapping of members based on
292** that JSON description.
293*/
294typedef struct sqlite3_kvvfs_methods sqlite3_kvvfs_methods;
295struct sqlite3_kvvfs_methods {
296 int (*xRead)(const char *zClass, const char *zKey, char *zBuf, int nBuf);
297 int (*xWrite)(const char *zClass, const char *zKey, const char *zData);
298 int (*xDelete)(const char *zClass, const char *zKey);
299 const int nKeySize;
300};
301
302/*
303** This object holds the kvvfs I/O methods which may be swapped out
304** for JavaScript-side implementations in WASM builds. In such builds
305** it cannot be const, but in native builds it should be so that
306** the compiler can hopefully optimize this level of indirection out.
307** That said, kvvfs is intended primarily for use in WASM builds.
308**
309** Note that this is not explicitly flagged as static because the
310** amalgamation build will tag it with SQLITE_PRIVATE.
311*/
312#ifndef SQLITE_WASM
313const
314#endif
315sqlite3_kvvfs_methods sqlite3KvvfsMethods = {
316kvstorageRead,
317kvstorageWrite,
318kvstorageDelete,
319KVSTORAGE_KEY_SZ
320};
drh59ece7e2022-09-07 17:29:22321
drhf7377d52022-09-09 14:22:41322/****** Utility subroutines ************************************************/
drh59ece7e2022-09-07 17:29:22323
drh59ece7e2022-09-07 17:29:22324/*
325** Encode binary into the text encoded used to persist on disk.
326** The output text is stored in aOut[], which must be at least
327** nData+1 bytes in length.
328**
329** Return the actual length of the encoded text, not counting the
330** zero terminator at the end.
drhf7377d52022-09-09 14:22:41331**
332** Encoding format
333** ---------------
334**
335** * Non-zero bytes are encoded as upper-case hexadecimal
336**
337** * A sequence of one or more zero-bytes that are not at the
338** beginning of the buffer are encoded as a little-endian
339** base-26 number using a..z. "a" means 0. "b" means 1,
340** "z" means 25. "ab" means 26. "ac" means 52. And so forth.
341**
342** * Because there is no overlap between the encoding characters
343** of hexadecimal and base-26 numbers, it is always clear where
344** one stops and the next begins.
drh59ece7e2022-09-07 17:29:22345*/
346static int kvvfsEncode(const char *aData, int nData, char *aOut){
347 int i, j;
drhe3485ee2022-09-08 16:27:50348 const unsigned char *a = (const unsigned char*)aData;
drh59ece7e2022-09-07 17:29:22349 for(i=j=0; i<nData; i++){
350 unsigned char c = a[i];
351 if( c!=0 ){
352 aOut[j++] = "0123456789ABCDEF"[c>>4];
353 aOut[j++] = "0123456789ABCDEF"[c&0xf];
354 }else{
355 /* A sequence of 1 or more zeros is stored as a little-endian
356 ** base-26 number using a..z as the digits. So one zero is "b".
drhcb941322022-09-08 15:48:01357 ** Two zeros is "c". 25 zeros is "z", 26 zeros is "ab", 27 is "bb",
358 ** and so forth.
drh59ece7e2022-09-07 17:29:22359 */
360 int k;
drh126976c2022-09-09 11:41:54361 for(k=1; i+k<nData && a[i+k]==0; k++){}
362 i += k-1;
drh59ece7e2022-09-07 17:29:22363 while( k>0 ){
364 aOut[j++] = 'a'+(k%26);
365 k /= 26;
366 }
367 }
368 }
369 aOut[j] = 0;
370 return j;
371}
372
drh6acd7b02022-09-12 17:44:35373static const signed char kvvfsHexValue[256] = {
374 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
375 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
376 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
377 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
378 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
379 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
380 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
381 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
382
383 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
384 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
385 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
386 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
387 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
388 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
389 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
390 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
391};
drh59ece7e2022-09-07 17:29:22392
393/*
394** Decode the text encoding back to binary. The binary content is
395** written into pOut, which must be at least nOut bytes in length.
drhcb941322022-09-08 15:48:01396**
397** The return value is the number of bytes actually written into aOut[].
drh59ece7e2022-09-07 17:29:22398*/
drh6acd7b02022-09-12 17:44:35399static int kvvfsDecode(const char *a, char *aOut, int nOut){
drhe3485ee2022-09-08 16:27:50400 int i, j;
drh59ece7e2022-09-07 17:29:22401 int c;
drh6acd7b02022-09-12 17:44:35402 const unsigned char *aIn = (const unsigned char*)a;
drh59ece7e2022-09-07 17:29:22403 i = 0;
404 j = 0;
drh6acd7b02022-09-12 17:44:35405 while( 1 ){
406 c = kvvfsHexValue[aIn[i]];
407 if( c<0 ){
drh59ece7e2022-09-07 17:29:22408 int n = 0;
drhcb941322022-09-08 15:48:01409 int mult = 1;
drh6acd7b02022-09-12 17:44:35410 c = aIn[i];
411 if( c==0 ) break;
drh59ece7e2022-09-07 17:29:22412 while( c>='a' && c<='z' ){
drhcb941322022-09-08 15:48:01413 n += (c - 'a')*mult;
414 mult *= 26;
drh59ece7e2022-09-07 17:29:22415 c = aIn[++i];
416 }
417 if( j+n>nOut ) return -1;
drh6acd7b02022-09-12 17:44:35418 memset(&aOut[j], 0, n);
419 j += n;
peter.d.reid576fe902022-12-31 05:19:45420 if( c==0 || mult==1 ) break; /* progress stalled if mult==1 */
drh59ece7e2022-09-07 17:29:22421 }else{
drh6acd7b02022-09-12 17:44:35422 aOut[j] = c<<4;
423 c = kvvfsHexValue[aIn[++i]];
424 if( c<0 ) break;
425 aOut[j++] += c;
426 i++;
drh59ece7e2022-09-07 17:29:22427 }
428 }
429 return j;
430}
431
432/*
drhcb941322022-09-08 15:48:01433** Decode a complete journal file. Allocate space in pFile->aJrnl
434** and store the decoding there. Or leave pFile->aJrnl set to NULL
435** if an error is encountered.
436**
drhf7377d52022-09-09 14:22:41437** The first few characters of the text encoding will be a little-endian
drhcb941322022-09-08 15:48:01438** base-26 number (digits a..z) that is the total number of bytes
drhf7377d52022-09-09 14:22:41439** in the decoded journal file image. This base-26 number is followed
440** by a single space, then the encoding of the journal. The space
441** separator is required to act as a terminator for the base-26 number.
drhcb941322022-09-08 15:48:01442*/
443static void kvvfsDecodeJournal(
444 KVVfsFile *pFile, /* Store decoding in pFile->aJrnl */
445 const char *zTxt, /* Text encoding. Zero-terminated */
446 int nTxt /* Bytes in zTxt, excluding zero terminator */
447){
drha50d3b72022-09-17 18:31:31448 unsigned int n = 0;
drhcb941322022-09-08 15:48:01449 int c, i, mult;
450 i = 0;
451 mult = 1;
drhf7377d52022-09-09 14:22:41452 while( (c = zTxt[i++])>='a' && c<='z' ){
drhcb941322022-09-08 15:48:01453 n += (zTxt[i] - 'a')*mult;
454 mult *= 26;
drhcb941322022-09-08 15:48:01455 }
456 sqlite3_free(pFile->aJrnl);
457 pFile->aJrnl = sqlite3_malloc64( n );
458 if( pFile->aJrnl==0 ){
459 pFile->nJrnl = 0;
460 return;
461 }
462 pFile->nJrnl = n;
463 n = kvvfsDecode(zTxt+i, pFile->aJrnl, pFile->nJrnl);
464 if( n<pFile->nJrnl ){
465 sqlite3_free(pFile->aJrnl);
466 pFile->aJrnl = 0;
467 pFile->nJrnl = 0;
468 }
469}
470
471/*
drhf7377d52022-09-09 14:22:41472** Read or write the "sz" element, containing the database file size.
473*/
474static sqlite3_int64 kvvfsReadFileSize(KVVfsFile *pFile){
475 char zData[50];
476 zData[0] = 0;
stephand35b5582022-10-09 13:19:27477 sqlite3KvvfsMethods.xRead(pFile->zClass, "sz", zData, sizeof(zData)-1);
drhf7377d52022-09-09 14:22:41478 return strtoll(zData, 0, 0);
479}
stephand22cfa82022-09-16 01:08:06480static int kvvfsWriteFileSize(KVVfsFile *pFile, sqlite3_int64 sz){
drhf7377d52022-09-09 14:22:41481 char zData[50];
482 sqlite3_snprintf(sizeof(zData), zData, "%lld", sz);
stephand35b5582022-10-09 13:19:27483 return sqlite3KvvfsMethods.xWrite(pFile->zClass, "sz", zData);
drhf7377d52022-09-09 14:22:41484}
485
drh25f62502022-09-09 16:16:33486/****** sqlite3_io_methods methods ******************************************/
drhf7377d52022-09-09 14:22:41487
488/*
489** Close an kvvfs-file.
490*/
491static int kvvfsClose(sqlite3_file *pProtoFile){
492 KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
drhf7377d52022-09-09 14:22:41493
drh7585f492022-09-10 18:20:59494 SQLITE_KV_LOG(("xClose %s %s\n", pFile->zClass,
drh25f62502022-09-09 16:16:33495 pFile->isJournal ? "journal" : "db"));
drhf7377d52022-09-09 14:22:41496 sqlite3_free(pFile->aJrnl);
stephanfed255d2022-12-03 11:51:29497 sqlite3_free(pFile->aData);
drhf7377d52022-09-09 14:22:41498 return SQLITE_OK;
499}
500
501/*
drh59ece7e2022-09-07 17:29:22502** Read from the -journal file.
503*/
drhf7377d52022-09-09 14:22:41504static int kvvfsReadJrnl(
505 sqlite3_file *pProtoFile,
drh59ece7e2022-09-07 17:29:22506 void *zBuf,
507 int iAmt,
508 sqlite_int64 iOfst
509){
drhf7377d52022-09-09 14:22:41510 KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
drh59ece7e2022-09-07 17:29:22511 assert( pFile->isJournal );
drh7585f492022-09-10 18:20:59512 SQLITE_KV_LOG(("xRead('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
drh59ece7e2022-09-07 17:29:22513 if( pFile->aJrnl==0 ){
drhc6c9c6a2022-09-10 18:38:21514 int szTxt = kvstorageRead(pFile->zClass, "jrnl", 0, 0);
drh59ece7e2022-09-07 17:29:22515 char *aTxt;
516 if( szTxt<=4 ){
517 return SQLITE_IOERR;
518 }
519 aTxt = sqlite3_malloc64( szTxt+1 );
520 if( aTxt==0 ) return SQLITE_NOMEM;
drh25f62502022-09-09 16:16:33521 kvstorageRead(pFile->zClass, "jrnl", aTxt, szTxt+1);
drh59ece7e2022-09-07 17:29:22522 kvvfsDecodeJournal(pFile, aTxt, szTxt);
523 sqlite3_free(aTxt);
drhe3485ee2022-09-08 16:27:50524 if( pFile->aJrnl==0 ) return SQLITE_IOERR;
drh59ece7e2022-09-07 17:29:22525 }
526 if( iOfst+iAmt>pFile->nJrnl ){
527 return SQLITE_IOERR_SHORT_READ;
528 }
drhe3485ee2022-09-08 16:27:50529 memcpy(zBuf, pFile->aJrnl+iOfst, iAmt);
drh59ece7e2022-09-07 17:29:22530 return SQLITE_OK;
531}
532
533/*
534** Read from the database file.
535*/
drhf7377d52022-09-09 14:22:41536static int kvvfsReadDb(
537 sqlite3_file *pProtoFile,
drh59ece7e2022-09-07 17:29:22538 void *zBuf,
539 int iAmt,
540 sqlite_int64 iOfst
541){
drhf7377d52022-09-09 14:22:41542 KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
drhcb941322022-09-08 15:48:01543 unsigned int pgno;
drhe3485ee2022-09-08 16:27:50544 int got, n;
drhcb941322022-09-08 15:48:01545 char zKey[30];
stephanfed255d2022-12-03 11:51:29546 char *aData = pFile->aData;
drhcb941322022-09-08 15:48:01547 assert( iOfst>=0 );
548 assert( iAmt>=0 );
drh7585f492022-09-10 18:20:59549 SQLITE_KV_LOG(("xRead('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
drh126976c2022-09-09 11:41:54550 if( iOfst+iAmt>=512 ){
551 if( (iOfst % iAmt)!=0 ){
552 return SQLITE_IOERR_READ;
553 }
drhcb941322022-09-08 15:48:01554 if( (iAmt & (iAmt-1))!=0 || iAmt<512 || iAmt>65536 ){
555 return SQLITE_IOERR_READ;
556 }
557 pFile->szPage = iAmt;
drh126976c2022-09-09 11:41:54558 pgno = 1 + iOfst/iAmt;
559 }else{
560 pgno = 1;
drhcb941322022-09-08 15:48:01561 }
drhf7377d52022-09-09 14:22:41562 sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
stephanfed255d2022-12-03 11:51:29563 got = sqlite3KvvfsMethods.xRead(pFile->zClass, zKey,
564 aData, SQLITE_KVOS_SZ-1);
drhcb941322022-09-08 15:48:01565 if( got<0 ){
drh7cd81af2022-09-08 17:12:12566 n = 0;
567 }else{
568 aData[got] = 0;
drh126976c2022-09-09 11:41:54569 if( iOfst+iAmt<512 ){
drh756440f2022-09-16 15:19:04570 int k = iOfst+iAmt;
571 aData[k*2] = 0;
stephanfed255d2022-12-03 11:51:29572 n = kvvfsDecode(aData, &aData[2000], SQLITE_KVOS_SZ-2000);
drh126976c2022-09-09 11:41:54573 if( n>=iOfst+iAmt ){
drh756440f2022-09-16 15:19:04574 memcpy(zBuf, &aData[2000+iOfst], iAmt);
drh126976c2022-09-09 11:41:54575 n = iAmt;
576 }else{
577 n = 0;
578 }
579 }else{
580 n = kvvfsDecode(aData, zBuf, iAmt);
581 }
drhcb941322022-09-08 15:48:01582 }
drhcb941322022-09-08 15:48:01583 if( n<iAmt ){
584 memset(zBuf+n, 0, iAmt-n);
585 return SQLITE_IOERR_SHORT_READ;
586 }
587 return SQLITE_OK;
drh59ece7e2022-09-07 17:29:22588}
589
590
591/*
drh59ece7e2022-09-07 17:29:22592** Write into the -journal file.
593*/
drhf7377d52022-09-09 14:22:41594static int kvvfsWriteJrnl(
595 sqlite3_file *pProtoFile,
drh59ece7e2022-09-07 17:29:22596 const void *zBuf,
597 int iAmt,
598 sqlite_int64 iOfst
599){
drhf7377d52022-09-09 14:22:41600 KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
drhcb941322022-09-08 15:48:01601 sqlite3_int64 iEnd = iOfst+iAmt;
drh7585f492022-09-10 18:20:59602 SQLITE_KV_LOG(("xWrite('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
drhcb941322022-09-08 15:48:01603 if( iEnd>=0x10000000 ) return SQLITE_FULL;
604 if( pFile->aJrnl==0 || pFile->nJrnl<iEnd ){
605 char *aNew = sqlite3_realloc(pFile->aJrnl, iEnd);
606 if( aNew==0 ){
607 return SQLITE_IOERR_NOMEM;
608 }
609 pFile->aJrnl = aNew;
610 if( pFile->nJrnl<iOfst ){
611 memset(pFile->aJrnl+pFile->nJrnl, 0, iOfst-pFile->nJrnl);
612 }
613 pFile->nJrnl = iEnd;
614 }
615 memcpy(pFile->aJrnl+iOfst, zBuf, iAmt);
616 return SQLITE_OK;
drh59ece7e2022-09-07 17:29:22617}
618
619/*
drhcb941322022-09-08 15:48:01620** Write into the database file.
drh59ece7e2022-09-07 17:29:22621*/
drhf7377d52022-09-09 14:22:41622static int kvvfsWriteDb(
623 sqlite3_file *pProtoFile,
drh59ece7e2022-09-07 17:29:22624 const void *zBuf,
625 int iAmt,
626 sqlite_int64 iOfst
627){
drhf7377d52022-09-09 14:22:41628 KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
drhcb941322022-09-08 15:48:01629 unsigned int pgno;
630 char zKey[30];
stephanfed255d2022-12-03 11:51:29631 char *aData = pFile->aData;
drh7585f492022-09-10 18:20:59632 SQLITE_KV_LOG(("xWrite('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
drhcb941322022-09-08 15:48:01633 assert( iAmt>=512 && iAmt<=65536 );
634 assert( (iAmt & (iAmt-1))==0 );
drhf7b58da2022-10-27 12:46:17635 assert( pFile->szPage<0 || pFile->szPage==iAmt );
636 pFile->szPage = iAmt;
drhcb941322022-09-08 15:48:01637 pgno = 1 + iOfst/iAmt;
drhf7377d52022-09-09 14:22:41638 sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
drhe3485ee2022-09-08 16:27:50639 kvvfsEncode(zBuf, iAmt, aData);
stephand35b5582022-10-09 13:19:27640 if( sqlite3KvvfsMethods.xWrite(pFile->zClass, zKey, aData) ){
stephand22cfa82022-09-16 01:08:06641 return SQLITE_IOERR;
642 }
drhcb941322022-09-08 15:48:01643 if( iOfst+iAmt > pFile->szDb ){
644 pFile->szDb = iOfst + iAmt;
645 }
646 return SQLITE_OK;
drh59ece7e2022-09-07 17:29:22647}
648
drh59ece7e2022-09-07 17:29:22649/*
650** Truncate an kvvfs-file.
651*/
drhf7377d52022-09-09 14:22:41652static int kvvfsTruncateJrnl(sqlite3_file *pProtoFile, sqlite_int64 size){
drh59ece7e2022-09-07 17:29:22653 KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
drh7585f492022-09-10 18:20:59654 SQLITE_KV_LOG(("xTruncate('%s-journal',%lld)\n", pFile->zClass, size));
drhf7377d52022-09-09 14:22:41655 assert( size==0 );
stephand35b5582022-10-09 13:19:27656 sqlite3KvvfsMethods.xDelete(pFile->zClass, "jrnl");
drhf7377d52022-09-09 14:22:41657 sqlite3_free(pFile->aJrnl);
658 pFile->aJrnl = 0;
659 pFile->nJrnl = 0;
660 return SQLITE_OK;
661}
662static int kvvfsTruncateDb(sqlite3_file *pProtoFile, sqlite_int64 size){
663 KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
drhcb941322022-09-08 15:48:01664 if( pFile->szDb>size
665 && pFile->szPage>0
666 && (size % pFile->szPage)==0
667 ){
668 char zKey[50];
669 unsigned int pgno, pgnoMax;
drh7585f492022-09-10 18:20:59670 SQLITE_KV_LOG(("xTruncate('%s-db',%lld)\n", pFile->zClass, size));
drhcb941322022-09-08 15:48:01671 pgno = 1 + size/pFile->szPage;
672 pgnoMax = 2 + pFile->szDb/pFile->szPage;
673 while( pgno<=pgnoMax ){
drhf7377d52022-09-09 14:22:41674 sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
stephand35b5582022-10-09 13:19:27675 sqlite3KvvfsMethods.xDelete(pFile->zClass, zKey);
drhcb941322022-09-08 15:48:01676 pgno++;
677 }
678 pFile->szDb = size;
stephand22cfa82022-09-16 01:08:06679 return kvvfsWriteFileSize(pFile, size) ? SQLITE_IOERR : SQLITE_OK;
drhcb941322022-09-08 15:48:01680 }
681 return SQLITE_IOERR;
drh59ece7e2022-09-07 17:29:22682}
683
684/*
685** Sync an kvvfs-file.
686*/
drhf7377d52022-09-09 14:22:41687static int kvvfsSyncJrnl(sqlite3_file *pProtoFile, int flags){
drhe3485ee2022-09-08 16:27:50688 int i, n;
drh59ece7e2022-09-07 17:29:22689 KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
drhcb941322022-09-08 15:48:01690 char *zOut;
drh7585f492022-09-10 18:20:59691 SQLITE_KV_LOG(("xSync('%s-journal')\n", pFile->zClass));
drhcb941322022-09-08 15:48:01692 if( pFile->nJrnl<=0 ){
drhf7377d52022-09-09 14:22:41693 return kvvfsTruncateJrnl(pProtoFile, 0);
drhcb941322022-09-08 15:48:01694 }
695 zOut = sqlite3_malloc64( pFile->nJrnl*2 + 50 );
696 if( zOut==0 ){
697 return SQLITE_IOERR_NOMEM;
698 }
699 n = pFile->nJrnl;
700 i = 0;
701 do{
702 zOut[i++] = 'a' + (n%26);
703 n /= 26;
704 }while( n>0 );
drhf7377d52022-09-09 14:22:41705 zOut[i++] = ' ';
drhcb941322022-09-08 15:48:01706 kvvfsEncode(pFile->aJrnl, pFile->nJrnl, &zOut[i]);
stephand35b5582022-10-09 13:19:27707 i = sqlite3KvvfsMethods.xWrite(pFile->zClass, "jrnl", zOut);
drhcb941322022-09-08 15:48:01708 sqlite3_free(zOut);
stephand22cfa82022-09-16 01:08:06709 return i ? SQLITE_IOERR : SQLITE_OK;
drh59ece7e2022-09-07 17:29:22710}
drhf7377d52022-09-09 14:22:41711static int kvvfsSyncDb(sqlite3_file *pProtoFile, int flags){
drh84e50762022-09-16 11:37:01712 return SQLITE_OK;
drhf7377d52022-09-09 14:22:41713}
drh59ece7e2022-09-07 17:29:22714
715/*
716** Return the current file-size of an kvvfs-file.
717*/
drhf7377d52022-09-09 14:22:41718static int kvvfsFileSizeJrnl(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
drh59ece7e2022-09-07 17:29:22719 KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
drh7585f492022-09-10 18:20:59720 SQLITE_KV_LOG(("xFileSize('%s-journal')\n", pFile->zClass));
drhf7377d52022-09-09 14:22:41721 *pSize = pFile->nJrnl;
722 return SQLITE_OK;
723}
724static int kvvfsFileSizeDb(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
725 KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
drh7585f492022-09-10 18:20:59726 SQLITE_KV_LOG(("xFileSize('%s-db')\n", pFile->zClass));
drhf7377d52022-09-09 14:22:41727 if( pFile->szDb>=0 ){
728 *pSize = pFile->szDb;
drhcb941322022-09-08 15:48:01729 }else{
drhf7377d52022-09-09 14:22:41730 *pSize = kvvfsReadFileSize(pFile);
drhcb941322022-09-08 15:48:01731 }
732 return SQLITE_OK;
drh59ece7e2022-09-07 17:29:22733}
734
735/*
736** Lock an kvvfs-file.
737*/
drhe3485ee2022-09-08 16:27:50738static int kvvfsLock(sqlite3_file *pProtoFile, int eLock){
drh59ece7e2022-09-07 17:29:22739 KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
drhcb941322022-09-08 15:48:01740 assert( !pFile->isJournal );
drh7585f492022-09-10 18:20:59741 SQLITE_KV_LOG(("xLock(%s,%d)\n", pFile->zClass, eLock));
drh126976c2022-09-09 11:41:54742
drhcb941322022-09-08 15:48:01743 if( eLock!=SQLITE_LOCK_NONE ){
744 pFile->szDb = kvvfsReadFileSize(pFile);
745 }
746 return SQLITE_OK;
drh59ece7e2022-09-07 17:29:22747}
748
749/*
750** Unlock an kvvfs-file.
751*/
drhe3485ee2022-09-08 16:27:50752static int kvvfsUnlock(sqlite3_file *pProtoFile, int eLock){
drh59ece7e2022-09-07 17:29:22753 KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
drhcb941322022-09-08 15:48:01754 assert( !pFile->isJournal );
drh7585f492022-09-10 18:20:59755 SQLITE_KV_LOG(("xUnlock(%s,%d)\n", pFile->zClass, eLock));
drhcb941322022-09-08 15:48:01756 if( eLock==SQLITE_LOCK_NONE ){
757 pFile->szDb = -1;
758 }
759 return SQLITE_OK;
drh59ece7e2022-09-07 17:29:22760}
761
762/*
763** Check if another file-handle holds a RESERVED lock on an kvvfs-file.
764*/
drhe3485ee2022-09-08 16:27:50765static int kvvfsCheckReservedLock(sqlite3_file *pProtoFile, int *pResOut){
drh7585f492022-09-10 18:20:59766 SQLITE_KV_LOG(("xCheckReservedLock\n"));
drh59ece7e2022-09-07 17:29:22767 *pResOut = 0;
drhe3485ee2022-09-08 16:27:50768 return SQLITE_OK;
drh59ece7e2022-09-07 17:29:22769}
770
771/*
772** File control method. For custom operations on an kvvfs-file.
773*/
drh84e50762022-09-16 11:37:01774static int kvvfsFileControlJrnl(sqlite3_file *pProtoFile, int op, void *pArg){
775 SQLITE_KV_LOG(("xFileControl(%d) on journal\n", op));
776 return SQLITE_NOTFOUND;
777}
778static int kvvfsFileControlDb(sqlite3_file *pProtoFile, int op, void *pArg){
779 SQLITE_KV_LOG(("xFileControl(%d) on database\n", op));
780 if( op==SQLITE_FCNTL_SYNC ){
781 KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
782 int rc = SQLITE_OK;
783 SQLITE_KV_LOG(("xSync('%s-db')\n", pFile->zClass));
784 if( pFile->szDb>0 && 0!=kvvfsWriteFileSize(pFile, pFile->szDb) ){
785 rc = SQLITE_IOERR;
786 }
787 return rc;
788 }
drhe3485ee2022-09-08 16:27:50789 return SQLITE_NOTFOUND;
drh59ece7e2022-09-07 17:29:22790}
791
792/*
793** Return the sector-size in bytes for an kvvfs-file.
794*/
795static int kvvfsSectorSize(sqlite3_file *pFile){
drhcb941322022-09-08 15:48:01796 return 512;
drh59ece7e2022-09-07 17:29:22797}
798
799/*
800** Return the device characteristic flags supported by an kvvfs-file.
801*/
drhe3485ee2022-09-08 16:27:50802static int kvvfsDeviceCharacteristics(sqlite3_file *pProtoFile){
drh59ece7e2022-09-07 17:29:22803 return 0;
804}
805
drh25f62502022-09-09 16:16:33806/****** sqlite3_vfs methods *************************************************/
drh59ece7e2022-09-07 17:29:22807
808/*
809** Open an kvvfs file handle.
810*/
811static int kvvfsOpen(
812 sqlite3_vfs *pProtoVfs,
813 const char *zName,
814 sqlite3_file *pProtoFile,
815 int flags,
816 int *pOutFlags
817){
drh59ece7e2022-09-07 17:29:22818 KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
drh9c17ee42022-10-27 14:00:21819 if( zName==0 ) zName = "";
drh7585f492022-09-10 18:20:59820 SQLITE_KV_LOG(("xOpen(\"%s\")\n", zName));
drh25f62502022-09-09 16:16:33821 if( strcmp(zName, "local")==0
822 || strcmp(zName, "session")==0
823 ){
824 pFile->isJournal = 0;
825 pFile->base.pMethods = &kvvfs_db_io_methods;
826 }else
827 if( strcmp(zName, "local-journal")==0
828 || strcmp(zName, "session-journal")==0
829 ){
drhf7377d52022-09-09 14:22:41830 pFile->isJournal = 1;
831 pFile->base.pMethods = &kvvfs_jrnl_io_methods;
832 }else{
drh25f62502022-09-09 16:16:33833 return SQLITE_CANTOPEN;
drhf7377d52022-09-09 14:22:41834 }
drh7585f492022-09-10 18:20:59835 if( zName[0]=='s' ){
drhc6c9c6a2022-09-10 18:38:21836 pFile->zClass = "session";
drh7585f492022-09-10 18:20:59837 }else{
drhc6c9c6a2022-09-10 18:38:21838 pFile->zClass = "local";
drh7585f492022-09-10 18:20:59839 }
stephanfed255d2022-12-03 11:51:29840 pFile->aData = sqlite3_malloc64(SQLITE_KVOS_SZ);
841 if( pFile->aData==0 ){
842 return SQLITE_NOMEM;
843 }
drh25f62502022-09-09 16:16:33844 pFile->aJrnl = 0;
845 pFile->nJrnl = 0;
drhcb941322022-09-08 15:48:01846 pFile->szPage = -1;
847 pFile->szDb = -1;
drhcb941322022-09-08 15:48:01848 return SQLITE_OK;
drh59ece7e2022-09-07 17:29:22849}
850
851/*
852** Delete the file located at zPath. If the dirSync argument is true,
853** ensure the file-system modifications are synced to disk before
854** returning.
855*/
856static int kvvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
drh25f62502022-09-09 16:16:33857 if( strcmp(zPath, "local-journal")==0 ){
stephand35b5582022-10-09 13:19:27858 sqlite3KvvfsMethods.xDelete("local", "jrnl");
drh25f62502022-09-09 16:16:33859 }else
860 if( strcmp(zPath, "session-journal")==0 ){
stephand35b5582022-10-09 13:19:27861 sqlite3KvvfsMethods.xDelete("session", "jrnl");
drh59ece7e2022-09-07 17:29:22862 }
863 return SQLITE_OK;
864}
865
866/*
867** Test for access permissions. Return true if the requested permission
868** is available, or false otherwise.
869*/
870static int kvvfsAccess(
drhcb941322022-09-08 15:48:01871 sqlite3_vfs *pProtoVfs,
drh59ece7e2022-09-07 17:29:22872 const char *zPath,
873 int flags,
874 int *pResOut
875){
drh7585f492022-09-10 18:20:59876 SQLITE_KV_LOG(("xAccess(\"%s\")\n", zPath));
drh25f62502022-09-09 16:16:33877 if( strcmp(zPath, "local-journal")==0 ){
stephand35b5582022-10-09 13:19:27878 *pResOut = sqlite3KvvfsMethods.xRead("local", "jrnl", 0, 0)>0;
drh25f62502022-09-09 16:16:33879 }else
880 if( strcmp(zPath, "session-journal")==0 ){
stephand35b5582022-10-09 13:19:27881 *pResOut = sqlite3KvvfsMethods.xRead("session", "jrnl", 0, 0)>0;
drh25f62502022-09-09 16:16:33882 }else
883 if( strcmp(zPath, "local")==0 ){
stephand35b5582022-10-09 13:19:27884 *pResOut = sqlite3KvvfsMethods.xRead("local", "sz", 0, 0)>0;
drh25f62502022-09-09 16:16:33885 }else
886 if( strcmp(zPath, "session")==0 ){
stephand35b5582022-10-09 13:19:27887 *pResOut = sqlite3KvvfsMethods.xRead("session", "sz", 0, 0)>0;
drh25f62502022-09-09 16:16:33888 }else
889 {
drh126976c2022-09-09 11:41:54890 *pResOut = 0;
drhcb941322022-09-08 15:48:01891 }
drh7585f492022-09-10 18:20:59892 SQLITE_KV_LOG(("xAccess returns %d\n",*pResOut));
drh59ece7e2022-09-07 17:29:22893 return SQLITE_OK;
894}
895
896/*
897** Populate buffer zOut with the full canonical pathname corresponding
898** to the pathname in zPath. zOut is guaranteed to point to a buffer
899** of at least (INST_MAX_PATHNAME+1) bytes.
900*/
901static int kvvfsFullPathname(
902 sqlite3_vfs *pVfs,
903 const char *zPath,
904 int nOut,
905 char *zOut
906){
drh6acd7b02022-09-12 17:44:35907 size_t nPath;
drhbb195122022-09-12 18:10:41908#ifdef SQLITE_OS_KV_ALWAYS_LOCAL
909 zPath = "local";
910#endif
drh6acd7b02022-09-12 17:44:35911 nPath = strlen(zPath);
drh7585f492022-09-10 18:20:59912 SQLITE_KV_LOG(("xFullPathname(\"%s\")\n", zPath));
drh59ece7e2022-09-07 17:29:22913 if( nOut<nPath+1 ) nPath = nOut - 1;
914 memcpy(zOut, zPath, nPath);
drhe3485ee2022-09-08 16:27:50915 zOut[nPath] = 0;
drh59ece7e2022-09-07 17:29:22916 return SQLITE_OK;
917}
918
919/*
920** Open the dynamic library located at zPath and return a handle.
921*/
922static void *kvvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
923 return 0;
924}
925
926/*
927** Populate the buffer pointed to by zBufOut with nByte bytes of
928** random data.
929*/
930static int kvvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
931 memset(zBufOut, 0, nByte);
932 return nByte;
933}
934
935/*
936** Sleep for nMicro microseconds. Return the number of microseconds
937** actually slept.
938*/
939static int kvvfsSleep(sqlite3_vfs *pVfs, int nMicro){
940 return SQLITE_OK;
941}
942
943/*
944** Return the current time as a Julian Day number in *pTimeOut.
945*/
946static int kvvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
drhd8bb0b52022-09-12 19:29:34947 sqlite3_int64 i = 0;
948 int rc;
949 rc = kvvfsCurrentTimeInt64(0, &i);
950 *pTimeOut = i/86400000.0;
951 return rc;
drh59ece7e2022-09-07 17:29:22952}
drhd8bb0b52022-09-12 19:29:34953#include <sys/time.h>
drh59ece7e2022-09-07 17:29:22954static int kvvfsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
drhd8bb0b52022-09-12 19:29:34955 static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
956 struct timeval sNow;
957 (void)gettimeofday(&sNow, 0); /* Cannot fail given valid arguments */
958 *pTimeOut = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
drh59ece7e2022-09-07 17:29:22959 return SQLITE_OK;
960}
drh20a9ed12022-09-17 18:29:49961#endif /* SQLITE_OS_KV || SQLITE_OS_UNIX */
drh59ece7e2022-09-07 17:29:22962
drh20a9ed12022-09-17 18:29:49963#if SQLITE_OS_KV
drhe3485ee2022-09-08 16:27:50964/*
drh7585f492022-09-10 18:20:59965** This routine is called initialize the KV-vfs as the default VFS.
drh59ece7e2022-09-07 17:29:22966*/
drh7585f492022-09-10 18:20:59967int sqlite3_os_init(void){
drh20a9ed12022-09-17 18:29:49968 return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 1);
drh59ece7e2022-09-07 17:29:22969}
drh7585f492022-09-10 18:20:59970int sqlite3_os_end(void){
971 return SQLITE_OK;
972}
973#endif /* SQLITE_OS_KV */
drh20a9ed12022-09-17 18:29:49974
975#if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
976int sqlite3KvvfsInit(void){
977 return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 0);
978}
979#endif