xref: /sqlite-3.40.0/src/os_kv.c (revision ef9cd12e)
1 /*
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 */
17 #include <sqliteInt.h>
18 #if SQLITE_OS_KV || (SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL))
19 
20 /*****************************************************************************
21 ** Debugging logic
22 */
23 
24 /* SQLITE_KV_TRACE() is used for tracing calls to kvstorage routines. */
25 #if 0
26 #define SQLITE_KV_TRACE(X)  printf X;
27 #else
28 #define SQLITE_KV_TRACE(X)
29 #endif
30 
31 /* SQLITE_KV_LOG() is used for tracing calls to the VFS interface */
32 #if 0
33 #define SQLITE_KV_LOG(X)  printf X;
34 #else
35 #define SQLITE_KV_LOG(X)
36 #endif
37 
38 
39 /*
40 ** Forward declaration of objects used by this VFS implementation
41 */
42 typedef struct KVVfsFile KVVfsFile;
43 
44 /* A single open file.  There are only two files represented by this
45 ** VFS - the database and the rollback journal.
46 */
47 struct KVVfsFile {
48   sqlite3_file base;              /* IO methods */
49   const char *zClass;             /* Storage class */
50   int isJournal;                  /* True if this is a journal file */
51   unsigned int nJrnl;             /* Space allocated for aJrnl[] */
52   char *aJrnl;                    /* Journal content */
53   int szPage;                     /* Last known page size */
54   sqlite3_int64 szDb;             /* Database file size.  -1 means unknown */
55 };
56 
57 /*
58 ** Methods for KVVfsFile
59 */
60 static int kvvfsClose(sqlite3_file*);
61 static int kvvfsReadDb(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
62 static int kvvfsReadJrnl(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
63 static int kvvfsWriteDb(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
64 static int kvvfsWriteJrnl(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
65 static int kvvfsTruncateDb(sqlite3_file*, sqlite3_int64 size);
66 static int kvvfsTruncateJrnl(sqlite3_file*, sqlite3_int64 size);
67 static int kvvfsSyncDb(sqlite3_file*, int flags);
68 static int kvvfsSyncJrnl(sqlite3_file*, int flags);
69 static int kvvfsFileSizeDb(sqlite3_file*, sqlite3_int64 *pSize);
70 static int kvvfsFileSizeJrnl(sqlite3_file*, sqlite3_int64 *pSize);
71 static int kvvfsLock(sqlite3_file*, int);
72 static int kvvfsUnlock(sqlite3_file*, int);
73 static int kvvfsCheckReservedLock(sqlite3_file*, int *pResOut);
74 static int kvvfsFileControlDb(sqlite3_file*, int op, void *pArg);
75 static int kvvfsFileControlJrnl(sqlite3_file*, int op, void *pArg);
76 static int kvvfsSectorSize(sqlite3_file*);
77 static int kvvfsDeviceCharacteristics(sqlite3_file*);
78 
79 /*
80 ** Methods for sqlite3_vfs
81 */
82 static int kvvfsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
83 static int kvvfsDelete(sqlite3_vfs*, const char *zName, int syncDir);
84 static int kvvfsAccess(sqlite3_vfs*, const char *zName, int flags, int *);
85 static int kvvfsFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
86 static void *kvvfsDlOpen(sqlite3_vfs*, const char *zFilename);
87 static int kvvfsRandomness(sqlite3_vfs*, int nByte, char *zOut);
88 static int kvvfsSleep(sqlite3_vfs*, int microseconds);
89 static int kvvfsCurrentTime(sqlite3_vfs*, double*);
90 static int kvvfsCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
91 
92 static sqlite3_vfs sqlite3OsKvvfsObject = {
93   1,                              /* iVersion */
94   sizeof(KVVfsFile),              /* szOsFile */
95   1024,                           /* mxPathname */
96   0,                              /* pNext */
97   "kvvfs",                        /* zName */
98   0,                              /* pAppData */
99   kvvfsOpen,                      /* xOpen */
100   kvvfsDelete,                    /* xDelete */
101   kvvfsAccess,                    /* xAccess */
102   kvvfsFullPathname,              /* xFullPathname */
103   kvvfsDlOpen,                    /* xDlOpen */
104   0,                              /* xDlError */
105   0,                              /* xDlSym */
106   0,                              /* xDlClose */
107   kvvfsRandomness,                /* xRandomness */
108   kvvfsSleep,                     /* xSleep */
109   kvvfsCurrentTime,               /* xCurrentTime */
110   0,                              /* xGetLastError */
111   kvvfsCurrentTimeInt64           /* xCurrentTimeInt64 */
112 };
113 
114 /* Methods for sqlite3_file objects referencing a database file
115 */
116 static sqlite3_io_methods kvvfs_db_io_methods = {
117   1,                              /* iVersion */
118   kvvfsClose,                     /* xClose */
119   kvvfsReadDb,                    /* xRead */
120   kvvfsWriteDb,                   /* xWrite */
121   kvvfsTruncateDb,                /* xTruncate */
122   kvvfsSyncDb,                    /* xSync */
123   kvvfsFileSizeDb,                /* xFileSize */
124   kvvfsLock,                      /* xLock */
125   kvvfsUnlock,                    /* xUnlock */
126   kvvfsCheckReservedLock,         /* xCheckReservedLock */
127   kvvfsFileControlDb,             /* xFileControl */
128   kvvfsSectorSize,                /* xSectorSize */
129   kvvfsDeviceCharacteristics,     /* xDeviceCharacteristics */
130   0,                              /* xShmMap */
131   0,                              /* xShmLock */
132   0,                              /* xShmBarrier */
133   0,                              /* xShmUnmap */
134   0,                              /* xFetch */
135   0                               /* xUnfetch */
136 };
137 
138 /* Methods for sqlite3_file objects referencing a rollback journal
139 */
140 static sqlite3_io_methods kvvfs_jrnl_io_methods = {
141   1,                              /* iVersion */
142   kvvfsClose,                     /* xClose */
143   kvvfsReadJrnl,                  /* xRead */
144   kvvfsWriteJrnl,                 /* xWrite */
145   kvvfsTruncateJrnl,              /* xTruncate */
146   kvvfsSyncJrnl,                  /* xSync */
147   kvvfsFileSizeJrnl,              /* xFileSize */
148   kvvfsLock,                      /* xLock */
149   kvvfsUnlock,                    /* xUnlock */
150   kvvfsCheckReservedLock,         /* xCheckReservedLock */
151   kvvfsFileControlJrnl,           /* xFileControl */
152   kvvfsSectorSize,                /* xSectorSize */
153   kvvfsDeviceCharacteristics,     /* xDeviceCharacteristics */
154   0,                              /* xShmMap */
155   0,                              /* xShmLock */
156   0,                              /* xShmBarrier */
157   0,                              /* xShmUnmap */
158   0,                              /* xFetch */
159   0                               /* xUnfetch */
160 };
161 
162 /****** Storage subsystem **************************************************/
163 #include <sys/types.h>
164 #include <sys/stat.h>
165 #include <unistd.h>
166 
167 /* Forward declarations for the low-level storage engine
168 */
169 #define KVSTORAGE_KEY_SZ  32
170 
171 /* Expand the key name with an appropriate prefix and put the result
172 ** zKeyOut[].  The zKeyOut[] buffer is assumed to hold at least
173 ** KVSTORAGE_KEY_SZ bytes.
174 */
175 static void kvstorageMakeKey(
176   const char *zClass,
177   const char *zKeyIn,
178   char *zKeyOut
179 ){
180   sqlite3_snprintf(KVSTORAGE_KEY_SZ, zKeyOut, "kvvfs-%s-%s", zClass, zKeyIn);
181 }
182 
183 #ifdef __EMSCRIPTEN__
184 /* Provide Emscripten-based impls of kvstorageWrite/Read/Delete()... */
185 #include <emscripten.h>
186 #include <emscripten/console.h>
187 
188 /*
189 ** WASM_KEEP is identical to EMSCRIPTEN_KEEPALIVE but is not
190 ** Emscripten-specific. It explicitly includes marked functions for
191 ** export into the target wasm file without requiring explicit listing
192 ** of those functions in Emscripten's -sEXPORTED_FUNCTIONS=... list
193 ** (or equivalent in other build platforms). Any function with neither
194 ** this attribute nor which is listed as an explicit export will not
195 ** be exported from the wasm file (but may still be used internally
196 ** within the wasm file).
197 **
198 ** The functions in this filewhich require exporting are marked with
199 ** this flag. They may also be added to any explicit build-time export
200 ** list but need not be. All of these APIs are intended for use only
201 ** within the project's own JS/WASM code, and not by client code, so
202 ** an argument can be made for reducing their visibility by not
203 ** including them in any build-time export lists.
204 **
205 ** 2022-09-11: it's not yet _proven_ that this approach works in
206 ** non-Emscripten builds. If not, such builds will need to export
207 ** those using the --export=... wasm-ld flag (or equivalent). As of
208 ** this writing we are tied to Emscripten for various reasons
209 ** and cannot test the library with other build environments.
210 */
211 #define WASM_KEEP __attribute__((used,visibility("default")))
212 /*
213 ** An internal level of indirection for accessing the static
214 ** kvstorageMakeKey() from EM_JS()-generated functions. This must be
215 ** made available for export via Emscripten but is not intended to be
216 ** used from client code. If called with a NULL zKeyOut it is a no-op.
217 ** It returns KVSTORAGE_KEY_SZ, so JS code (which cannot see that
218 ** constant) may call it with NULL arguments to get the size of the
219 ** allocation they'll need for a kvvfs key.
220 **
221 ** Maintenance reminder: Emscripten will install this in the Module
222 ** init scope and will prefix its name with "_".
223 */
224 WASM_KEEP
225 int sqlite3_wasm__kvvfsMakeKey(const char *zClass, const char *zKeyIn,
226                                char *zKeyOut){
227   if( 0!=zKeyOut ) kvstorageMakeKey(zClass, zKeyIn, zKeyOut);
228   return KVSTORAGE_KEY_SZ;
229 }
230 /*
231 ** Internal helper for kvstorageWrite/Read/Delete() which creates a
232 ** storage key for the given zClass/zKeyIn combination. Returns a
233 ** pointer to the key: a C string allocated on the WASM stack, or 0 if
234 ** allocation fails. It is up to the caller to save/restore the stack
235 ** before/after this operation.
236 */
237 EM_JS(const char *, kvstorageMakeKeyOnJSStack,
238       (const char *zClass, const char *zKeyIn),{
239   if( 0==zClass || 0==zKeyIn) return 0;
240   const zXKey = stackAlloc(_sqlite3_wasm__kvvfsMakeKey(0,0,0));
241   if(zXKey) _sqlite3_wasm__kvvfsMakeKey(zClass, zKeyIn, zXKey);
242   return zXKey;
243 });
244 
245 /*
246 ** JS impl of kvstorageWrite(). Main docs are in the C impl. This impl
247 ** writes zData to the global sessionStorage (if zClass starts with
248 ** 's') or localStorage, using a storage key derived from zClass and
249 ** zKey.
250 */
251 EM_JS(int, kvstorageWrite,
252       (const char *zClass, const char *zKey, const char *zData),{
253   const stack = stackSave();
254   try {
255     const zXKey = kvstorageMakeKeyOnJSStack(zClass,zKey);
256     if(!zXKey) return 1/*OOM*/;
257     const jKey = UTF8ToString(zXKey);
258     /**
259        We could simplify this function and eliminate the
260        kvstorageMakeKey() symbol acrobatics if we'd simply hard-code
261        the key algo into the 3 functions which need it:
262 
263        const jKey = "kvvfs-"+UTF8ToString(zClass)+"-"+UTF8ToString(zKey);
264     */
265     ((115/*=='s'*/===getValue(zClass))
266      ? sessionStorage : localStorage).setItem(jKey, UTF8ToString(zData));
267   }catch(e){
268     console.error("kvstorageWrite()",e);
269     return 1; // Can't access SQLITE_xxx from here
270   }finally{
271     stackRestore(stack);
272   }
273   return 0;
274 });
275 
276 /*
277 ** JS impl of kvstorageDelete(). Main docs are in the C impl. This
278 ** impl generates a key derived from zClass and zKey, and removes the
279 ** matching entry (if any) from global sessionStorage (if zClass
280 ** starts with 's') or localStorage.
281 */
282 EM_JS(int, kvstorageDelete,
283       (const char *zClass, const char *zKey),{
284   const stack = stackSave();
285   try {
286     const zXKey = kvstorageMakeKeyOnJSStack(zClass,zKey);
287     if(!zXKey) return 1/*OOM*/;
288     const jKey = UTF8ToString(zXKey);
289     ((115/*=='s'*/===getValue(zClass))
290      ? sessionStorage : localStorage).removeItem(jKey);
291   }catch(e){
292     console.error("kvstorageDelete()",e);
293     return 1;
294   }finally{
295     stackRestore(stack);
296   }
297   return 0;
298 });
299 
300 /*
301 ** JS impl of kvstorageRead(). Main docs are in the C impl. This impl
302 ** reads its data from the global sessionStorage (if zClass starts
303 ** with 's') or localStorage, using a storage key derived from zClass
304 ** and zKey.
305 */
306 EM_JS(int, kvstorageRead,
307       (const char *zClass, const char *zKey, char *zBuf, int nBuf),{
308   const stack = stackSave();
309   try {
310     const zXKey = kvstorageMakeKeyOnJSStack(zClass,zKey);
311     if(!zXKey) return -3/*OOM*/;
312     const jKey = UTF8ToString(zXKey);
313     const jV = ((115/*=='s'*/===getValue(zClass))
314                 ? sessionStorage : localStorage).getItem(jKey);
315     if(!jV) return -1;
316     const nV = jV.length /* Note that we are relying 100% on v being
317                             ASCII so that jV.length is equal to the
318                             C-string's byte length. */;
319     if(nBuf<=0) return nV;
320     else if(1===nBuf){
321       setValue(zBuf, 0);
322       return nV;
323     }
324     const zV = allocateUTF8OnStack(jV);
325     if(nBuf > nV + 1) nBuf = nV + 1;
326     HEAPU8.copyWithin(zBuf, zV, zV + nBuf - 1);
327     setValue( zBuf + nBuf - 1, 0 );
328     return nBuf - 1;
329   }catch(e){
330     console.error("kvstorageRead()",e);
331     return -2;
332   }finally{
333     stackRestore(stack);
334   }
335 });
336 
337 /*
338 ** This function exists for (1) WASM testing purposes and (2) as a
339 ** hook to get Emscripten to export several EM_JS()-generated
340 ** functions (if we don't reference them from exported C functions
341 ** then they get stripped away at build time). It is not part of the
342 ** public API and its signature and semantics may change at any time.
343 ** It's not even part of the private API, for that matter - it's part
344 ** of the Emscripten C/JS/WASM glue.
345 */
346 WASM_KEEP
347 int sqlite3__wasm_emjs_kvvfs(int whichOp){
348   int rc = 0;
349   const char * zClass =
350     "sezzion" /*don't collide with "session" records!*/;
351   const char * zKey = "hello";
352   switch( whichOp ){
353     case 0: break;
354     case 1:
355       rc = kvstorageWrite(zClass, zKey, "world");
356       break;
357     case 2: {
358       char buffer[128] = {0};
359       char * zBuf = &buffer[0];
360       rc = kvstorageRead(zClass, zKey, zBuf, (int)sizeof(buffer));
361       emscripten_console_logf("kvstorageRead()=%d %s\n", rc, zBuf);
362       break;
363     }
364     case 3:
365       kvstorageDelete(zClass, zKey);
366       break;
367     case 4:
368       kvstorageMakeKeyOnJSStack(0,0);
369       break;
370     default: break;
371   }
372   return rc;
373 }
374 
375 #undef WASM_KEEP
376 #else /* end ifdef __EMSCRIPTEN__ */
377 /* Forward declarations for the low-level storage engine
378 */
379 static int kvstorageWrite(const char*, const char *zKey, const char *zData);
380 static int kvstorageDelete(const char*, const char *zKey);
381 static int kvstorageRead(const char*, const char *zKey, char *zBuf, int nBuf);
382 
383 /* Write content into a key.  zClass is the particular namespace of the
384 ** underlying key/value store to use - either "local" or "session".
385 **
386 ** Both zKey and zData are zero-terminated pure text strings.
387 **
388 ** Return the number of errors.
389 */
390 static int kvstorageWrite(
391   const char *zClass,
392   const char *zKey,
393   const char *zData
394 ){
395   FILE *fd;
396   char zXKey[KVSTORAGE_KEY_SZ];
397   kvstorageMakeKey(zClass, zKey, zXKey);
398   fd = fopen(zXKey, "wb");
399   if( fd ){
400     SQLITE_KV_TRACE(("KVVFS-WRITE  %-15s (%d) %.50s%s\n", zXKey,
401                  (int)strlen(zData), zData,
402                  strlen(zData)>50 ? "..." : ""));
403     fputs(zData, fd);
404     fclose(fd);
405     return 0;
406   }else{
407     return 1;
408   }
409 }
410 
411 /* Delete a key (with its corresponding data) from the key/value
412 ** namespace given by zClass.  If the key does not previously exist,
413 ** this routine is a no-op.
414 */
415 static int kvstorageDelete(const char *zClass, const char *zKey){
416   char zXKey[KVSTORAGE_KEY_SZ];
417   kvstorageMakeKey(zClass, zKey, zXKey);
418   unlink(zXKey);
419   SQLITE_KV_TRACE(("KVVFS-DELETE %-15s\n", zXKey));
420   return 0;
421 }
422 
423 /* Read the value associated with a zKey from the key/value namespace given
424 ** by zClass and put the text data associated with that key in the first
425 ** nBuf bytes of zBuf[].  The value might be truncated if zBuf is not large
426 ** enough to hold it all.  The value put into zBuf must always be zero
427 ** terminated, even if it gets truncated because nBuf is not large enough.
428 **
429 ** Return the total number of bytes in the data, without truncation, and
430 ** not counting the final zero terminator.   Return -1 if the key does
431 ** not exist.
432 **
433 ** If nBuf<=0 then this routine simply returns the size of the data without
434 ** actually reading it.
435 */
436 static int kvstorageRead(
437   const char *zClass,
438   const char *zKey,
439   char *zBuf,
440   int nBuf
441 ){
442   FILE *fd;
443   struct stat buf;
444   char zXKey[KVSTORAGE_KEY_SZ];
445   kvstorageMakeKey(zClass, zKey, zXKey);
446   if( access(zXKey, R_OK)!=0
447    || stat(zXKey, &buf)!=0
448    || !S_ISREG(buf.st_mode)
449   ){
450     SQLITE_KV_TRACE(("KVVFS-READ   %-15s (-1)\n", zXKey));
451     return -1;
452   }
453   if( nBuf<=0 ){
454     return (int)buf.st_size;
455   }else if( nBuf==1 ){
456     zBuf[0] = 0;
457     SQLITE_KV_TRACE(("KVVFS-READ   %-15s (%d)\n", zXKey,
458                  (int)buf.st_size));
459     return (int)buf.st_size;
460   }
461   if( nBuf > buf.st_size + 1 ){
462     nBuf = buf.st_size + 1;
463   }
464   fd = fopen(zXKey, "rb");
465   if( fd==0 ){
466     SQLITE_KV_TRACE(("KVVFS-READ   %-15s (-1)\n", zXKey));
467     return -1;
468   }else{
469     sqlite3_int64 n = fread(zBuf, 1, nBuf-1, fd);
470     fclose(fd);
471     zBuf[n] = 0;
472     SQLITE_KV_TRACE(("KVVFS-READ   %-15s (%lld) %.50s%s\n", zXKey,
473                  n, zBuf, n>50 ? "..." : ""));
474     return (int)n;
475   }
476 }
477 #endif /* ifdef __EMSCRIPTEN__ */
478 
479 /****** Utility subroutines ************************************************/
480 
481 /*
482 ** Encode binary into the text encoded used to persist on disk.
483 ** The output text is stored in aOut[], which must be at least
484 ** nData+1 bytes in length.
485 **
486 ** Return the actual length of the encoded text, not counting the
487 ** zero terminator at the end.
488 **
489 ** Encoding format
490 ** ---------------
491 **
492 **   *  Non-zero bytes are encoded as upper-case hexadecimal
493 **
494 **   *  A sequence of one or more zero-bytes that are not at the
495 **      beginning of the buffer are encoded as a little-endian
496 **      base-26 number using a..z.  "a" means 0.  "b" means 1,
497 **      "z" means 25.  "ab" means 26.  "ac" means 52.  And so forth.
498 **
499 **   *  Because there is no overlap between the encoding characters
500 **      of hexadecimal and base-26 numbers, it is always clear where
501 **      one stops and the next begins.
502 */
503 static int kvvfsEncode(const char *aData, int nData, char *aOut){
504   int i, j;
505   const unsigned char *a = (const unsigned char*)aData;
506   for(i=j=0; i<nData; i++){
507     unsigned char c = a[i];
508     if( c!=0 ){
509       aOut[j++] = "0123456789ABCDEF"[c>>4];
510       aOut[j++] = "0123456789ABCDEF"[c&0xf];
511     }else{
512       /* A sequence of 1 or more zeros is stored as a little-endian
513       ** base-26 number using a..z as the digits. So one zero is "b".
514       ** Two zeros is "c". 25 zeros is "z", 26 zeros is "ab", 27 is "bb",
515       ** and so forth.
516       */
517       int k;
518       for(k=1; i+k<nData && a[i+k]==0; k++){}
519       i += k-1;
520       while( k>0 ){
521         aOut[j++] = 'a'+(k%26);
522         k /= 26;
523       }
524     }
525   }
526   aOut[j] = 0;
527   return j;
528 }
529 
530 static const signed char kvvfsHexValue[256] = {
531   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
532   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
533   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
534    0,  1,  2,  3,  4,  5,  6,  7,    8,  9, -1, -1, -1, -1, -1, -1,
535   -1, 10, 11, 12, 13, 14, 15, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
536   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
537   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
538   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
539 
540   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
541   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
542   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
543   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
544   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
545   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
546   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
547   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1
548 };
549 
550 /*
551 ** Decode the text encoding back to binary.  The binary content is
552 ** written into pOut, which must be at least nOut bytes in length.
553 **
554 ** The return value is the number of bytes actually written into aOut[].
555 */
556 static int kvvfsDecode(const char *a, char *aOut, int nOut){
557   int i, j;
558   int c;
559   const unsigned char *aIn = (const unsigned char*)a;
560   i = 0;
561   j = 0;
562   while( 1 ){
563     c = kvvfsHexValue[aIn[i]];
564     if( c<0 ){
565       int n = 0;
566       int mult = 1;
567       c = aIn[i];
568       if( c==0 ) break;
569       while( c>='a' && c<='z' ){
570         n += (c - 'a')*mult;
571         mult *= 26;
572         c = aIn[++i];
573       }
574       if( j+n>nOut ) return -1;
575       memset(&aOut[j], 0, n);
576       j += n;
577       c = aIn[i];
578       if( c==0 ) break;
579     }else{
580       aOut[j] = c<<4;
581       c = kvvfsHexValue[aIn[++i]];
582       if( c<0 ) break;
583       aOut[j++] += c;
584       i++;
585     }
586   }
587   return j;
588 }
589 
590 /*
591 ** Decode a complete journal file.  Allocate space in pFile->aJrnl
592 ** and store the decoding there.  Or leave pFile->aJrnl set to NULL
593 ** if an error is encountered.
594 **
595 ** The first few characters of the text encoding will be a little-endian
596 ** base-26 number (digits a..z) that is the total number of bytes
597 ** in the decoded journal file image.  This base-26 number is followed
598 ** by a single space, then the encoding of the journal.  The space
599 ** separator is required to act as a terminator for the base-26 number.
600 */
601 static void kvvfsDecodeJournal(
602   KVVfsFile *pFile,      /* Store decoding in pFile->aJrnl */
603   const char *zTxt,      /* Text encoding.  Zero-terminated */
604   int nTxt               /* Bytes in zTxt, excluding zero terminator */
605 ){
606   unsigned int n = 0;
607   int c, i, mult;
608   i = 0;
609   mult = 1;
610   while( (c = zTxt[i++])>='a' && c<='z' ){
611     n += (zTxt[i] - 'a')*mult;
612     mult *= 26;
613   }
614   sqlite3_free(pFile->aJrnl);
615   pFile->aJrnl = sqlite3_malloc64( n );
616   if( pFile->aJrnl==0 ){
617     pFile->nJrnl = 0;
618     return;
619   }
620   pFile->nJrnl = n;
621   n = kvvfsDecode(zTxt+i, pFile->aJrnl, pFile->nJrnl);
622   if( n<pFile->nJrnl ){
623     sqlite3_free(pFile->aJrnl);
624     pFile->aJrnl = 0;
625     pFile->nJrnl = 0;
626   }
627 }
628 
629 /*
630 ** Read or write the "sz" element, containing the database file size.
631 */
632 static sqlite3_int64 kvvfsReadFileSize(KVVfsFile *pFile){
633   char zData[50];
634   zData[0] = 0;
635   kvstorageRead(pFile->zClass, "sz", zData, sizeof(zData)-1);
636   return strtoll(zData, 0, 0);
637 }
638 static int kvvfsWriteFileSize(KVVfsFile *pFile, sqlite3_int64 sz){
639   char zData[50];
640   sqlite3_snprintf(sizeof(zData), zData, "%lld", sz);
641   return kvstorageWrite(pFile->zClass, "sz", zData);
642 }
643 
644 /****** sqlite3_io_methods methods ******************************************/
645 
646 /*
647 ** Close an kvvfs-file.
648 */
649 static int kvvfsClose(sqlite3_file *pProtoFile){
650   KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
651 
652   SQLITE_KV_LOG(("xClose %s %s\n", pFile->zClass,
653              pFile->isJournal ? "journal" : "db"));
654   sqlite3_free(pFile->aJrnl);
655   return SQLITE_OK;
656 }
657 
658 /*
659 ** Read from the -journal file.
660 */
661 static int kvvfsReadJrnl(
662   sqlite3_file *pProtoFile,
663   void *zBuf,
664   int iAmt,
665   sqlite_int64 iOfst
666 ){
667   KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
668   assert( pFile->isJournal );
669   SQLITE_KV_LOG(("xRead('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
670   if( pFile->aJrnl==0 ){
671     int szTxt = kvstorageRead(pFile->zClass, "jrnl", 0, 0);
672     char *aTxt;
673     if( szTxt<=4 ){
674       return SQLITE_IOERR;
675     }
676     aTxt = sqlite3_malloc64( szTxt+1 );
677     if( aTxt==0 ) return SQLITE_NOMEM;
678     kvstorageRead(pFile->zClass, "jrnl", aTxt, szTxt+1);
679     kvvfsDecodeJournal(pFile, aTxt, szTxt);
680     sqlite3_free(aTxt);
681     if( pFile->aJrnl==0 ) return SQLITE_IOERR;
682   }
683   if( iOfst+iAmt>pFile->nJrnl ){
684     return SQLITE_IOERR_SHORT_READ;
685   }
686   memcpy(zBuf, pFile->aJrnl+iOfst, iAmt);
687   return SQLITE_OK;
688 }
689 
690 /*
691 ** Read from the database file.
692 */
693 static int kvvfsReadDb(
694   sqlite3_file *pProtoFile,
695   void *zBuf,
696   int iAmt,
697   sqlite_int64 iOfst
698 ){
699   KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
700   unsigned int pgno;
701   int got, n;
702   char zKey[30];
703   char aData[133073];
704   assert( iOfst>=0 );
705   assert( iAmt>=0 );
706   SQLITE_KV_LOG(("xRead('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
707   if( iOfst+iAmt>=512 ){
708     if( (iOfst % iAmt)!=0 ){
709       return SQLITE_IOERR_READ;
710     }
711     if( (iAmt & (iAmt-1))!=0 || iAmt<512 || iAmt>65536 ){
712       return SQLITE_IOERR_READ;
713     }
714     pFile->szPage = iAmt;
715     pgno = 1 + iOfst/iAmt;
716   }else{
717     pgno = 1;
718   }
719   sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
720   got = kvstorageRead(pFile->zClass, zKey, aData, sizeof(aData)-1);
721   if( got<0 ){
722     n = 0;
723   }else{
724     aData[got] = 0;
725     if( iOfst+iAmt<512 ){
726       int k = iOfst+iAmt;
727       aData[k*2] = 0;
728       n = kvvfsDecode(aData, &aData[2000], sizeof(aData)-2000);
729       if( n>=iOfst+iAmt ){
730         memcpy(zBuf, &aData[2000+iOfst], iAmt);
731         n = iAmt;
732       }else{
733         n = 0;
734       }
735     }else{
736       n = kvvfsDecode(aData, zBuf, iAmt);
737     }
738   }
739   if( n<iAmt ){
740     memset(zBuf+n, 0, iAmt-n);
741     return SQLITE_IOERR_SHORT_READ;
742   }
743   return SQLITE_OK;
744 }
745 
746 
747 /*
748 ** Write into the -journal file.
749 */
750 static int kvvfsWriteJrnl(
751   sqlite3_file *pProtoFile,
752   const void *zBuf,
753   int iAmt,
754   sqlite_int64 iOfst
755 ){
756   KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
757   sqlite3_int64 iEnd = iOfst+iAmt;
758   SQLITE_KV_LOG(("xWrite('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
759   if( iEnd>=0x10000000 ) return SQLITE_FULL;
760   if( pFile->aJrnl==0 || pFile->nJrnl<iEnd ){
761     char *aNew = sqlite3_realloc(pFile->aJrnl, iEnd);
762     if( aNew==0 ){
763       return SQLITE_IOERR_NOMEM;
764     }
765     pFile->aJrnl = aNew;
766     if( pFile->nJrnl<iOfst ){
767       memset(pFile->aJrnl+pFile->nJrnl, 0, iOfst-pFile->nJrnl);
768     }
769     pFile->nJrnl = iEnd;
770   }
771   memcpy(pFile->aJrnl+iOfst, zBuf, iAmt);
772   return SQLITE_OK;
773 }
774 
775 /*
776 ** Write into the database file.
777 */
778 static int kvvfsWriteDb(
779   sqlite3_file *pProtoFile,
780   const void *zBuf,
781   int iAmt,
782   sqlite_int64 iOfst
783 ){
784   KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
785   unsigned int pgno;
786   char zKey[30];
787   char aData[131073];
788   SQLITE_KV_LOG(("xWrite('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
789   assert( iAmt>=512 && iAmt<=65536 );
790   assert( (iAmt & (iAmt-1))==0 );
791   pgno = 1 + iOfst/iAmt;
792   sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
793   kvvfsEncode(zBuf, iAmt, aData);
794   if( kvstorageWrite(pFile->zClass, zKey, aData) ){
795     return SQLITE_IOERR;
796   }
797   if( iOfst+iAmt > pFile->szDb ){
798     pFile->szDb = iOfst + iAmt;
799   }
800   return SQLITE_OK;
801 }
802 
803 /*
804 ** Truncate an kvvfs-file.
805 */
806 static int kvvfsTruncateJrnl(sqlite3_file *pProtoFile, sqlite_int64 size){
807   KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
808   SQLITE_KV_LOG(("xTruncate('%s-journal',%lld)\n", pFile->zClass, size));
809   assert( size==0 );
810   kvstorageDelete(pFile->zClass, "jrnl");
811   sqlite3_free(pFile->aJrnl);
812   pFile->aJrnl = 0;
813   pFile->nJrnl = 0;
814   return SQLITE_OK;
815 }
816 static int kvvfsTruncateDb(sqlite3_file *pProtoFile, sqlite_int64 size){
817   KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
818   if( pFile->szDb>size
819    && pFile->szPage>0
820    && (size % pFile->szPage)==0
821   ){
822     char zKey[50];
823     unsigned int pgno, pgnoMax;
824     SQLITE_KV_LOG(("xTruncate('%s-db',%lld)\n", pFile->zClass, size));
825     pgno = 1 + size/pFile->szPage;
826     pgnoMax = 2 + pFile->szDb/pFile->szPage;
827     while( pgno<=pgnoMax ){
828       sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
829       kvstorageDelete(pFile->zClass, zKey);
830       pgno++;
831     }
832     pFile->szDb = size;
833     return kvvfsWriteFileSize(pFile, size) ? SQLITE_IOERR : SQLITE_OK;
834   }
835   return SQLITE_IOERR;
836 }
837 
838 /*
839 ** Sync an kvvfs-file.
840 */
841 static int kvvfsSyncJrnl(sqlite3_file *pProtoFile, int flags){
842   int i, n;
843   KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
844   char *zOut;
845   SQLITE_KV_LOG(("xSync('%s-journal')\n", pFile->zClass));
846   if( pFile->nJrnl<=0 ){
847     return kvvfsTruncateJrnl(pProtoFile, 0);
848   }
849   zOut = sqlite3_malloc64( pFile->nJrnl*2 + 50 );
850   if( zOut==0 ){
851     return SQLITE_IOERR_NOMEM;
852   }
853   n = pFile->nJrnl;
854   i = 0;
855   do{
856     zOut[i++] = 'a' + (n%26);
857     n /= 26;
858   }while( n>0 );
859   zOut[i++] = ' ';
860   kvvfsEncode(pFile->aJrnl, pFile->nJrnl, &zOut[i]);
861   i = kvstorageWrite(pFile->zClass, "jrnl", zOut);
862   sqlite3_free(zOut);
863   return i ? SQLITE_IOERR : SQLITE_OK;
864 }
865 static int kvvfsSyncDb(sqlite3_file *pProtoFile, int flags){
866   return SQLITE_OK;
867 }
868 
869 /*
870 ** Return the current file-size of an kvvfs-file.
871 */
872 static int kvvfsFileSizeJrnl(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
873   KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
874   SQLITE_KV_LOG(("xFileSize('%s-journal')\n", pFile->zClass));
875   *pSize = pFile->nJrnl;
876   return SQLITE_OK;
877 }
878 static int kvvfsFileSizeDb(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
879   KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
880   SQLITE_KV_LOG(("xFileSize('%s-db')\n", pFile->zClass));
881   if( pFile->szDb>=0 ){
882     *pSize = pFile->szDb;
883   }else{
884     *pSize = kvvfsReadFileSize(pFile);
885   }
886   return SQLITE_OK;
887 }
888 
889 /*
890 ** Lock an kvvfs-file.
891 */
892 static int kvvfsLock(sqlite3_file *pProtoFile, int eLock){
893   KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
894   assert( !pFile->isJournal );
895   SQLITE_KV_LOG(("xLock(%s,%d)\n", pFile->zClass, eLock));
896 
897   if( eLock!=SQLITE_LOCK_NONE ){
898     pFile->szDb = kvvfsReadFileSize(pFile);
899   }
900   return SQLITE_OK;
901 }
902 
903 /*
904 ** Unlock an kvvfs-file.
905 */
906 static int kvvfsUnlock(sqlite3_file *pProtoFile, int eLock){
907   KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
908   assert( !pFile->isJournal );
909   SQLITE_KV_LOG(("xUnlock(%s,%d)\n", pFile->zClass, eLock));
910   if( eLock==SQLITE_LOCK_NONE ){
911     pFile->szDb = -1;
912   }
913   return SQLITE_OK;
914 }
915 
916 /*
917 ** Check if another file-handle holds a RESERVED lock on an kvvfs-file.
918 */
919 static int kvvfsCheckReservedLock(sqlite3_file *pProtoFile, int *pResOut){
920   SQLITE_KV_LOG(("xCheckReservedLock\n"));
921   *pResOut = 0;
922   return SQLITE_OK;
923 }
924 
925 /*
926 ** File control method. For custom operations on an kvvfs-file.
927 */
928 static int kvvfsFileControlJrnl(sqlite3_file *pProtoFile, int op, void *pArg){
929   SQLITE_KV_LOG(("xFileControl(%d) on journal\n", op));
930   return SQLITE_NOTFOUND;
931 }
932 static int kvvfsFileControlDb(sqlite3_file *pProtoFile, int op, void *pArg){
933   SQLITE_KV_LOG(("xFileControl(%d) on database\n", op));
934   if( op==SQLITE_FCNTL_SYNC ){
935     KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
936     int rc = SQLITE_OK;
937     SQLITE_KV_LOG(("xSync('%s-db')\n", pFile->zClass));
938     if( pFile->szDb>0 && 0!=kvvfsWriteFileSize(pFile, pFile->szDb) ){
939       rc = SQLITE_IOERR;
940     }
941     return rc;
942   }
943   return SQLITE_NOTFOUND;
944 }
945 
946 /*
947 ** Return the sector-size in bytes for an kvvfs-file.
948 */
949 static int kvvfsSectorSize(sqlite3_file *pFile){
950   return 512;
951 }
952 
953 /*
954 ** Return the device characteristic flags supported by an kvvfs-file.
955 */
956 static int kvvfsDeviceCharacteristics(sqlite3_file *pProtoFile){
957   return 0;
958 }
959 
960 /****** sqlite3_vfs methods *************************************************/
961 
962 /*
963 ** Open an kvvfs file handle.
964 */
965 static int kvvfsOpen(
966   sqlite3_vfs *pProtoVfs,
967   const char *zName,
968   sqlite3_file *pProtoFile,
969   int flags,
970   int *pOutFlags
971 ){
972   KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
973   SQLITE_KV_LOG(("xOpen(\"%s\")\n", zName));
974   if( strcmp(zName, "local")==0
975    || strcmp(zName, "session")==0
976   ){
977     pFile->isJournal = 0;
978     pFile->base.pMethods = &kvvfs_db_io_methods;
979   }else
980   if( strcmp(zName, "local-journal")==0
981    || strcmp(zName, "session-journal")==0
982   ){
983     pFile->isJournal = 1;
984     pFile->base.pMethods = &kvvfs_jrnl_io_methods;
985   }else{
986     return SQLITE_CANTOPEN;
987   }
988   if( zName[0]=='s' ){
989     pFile->zClass = "session";
990   }else{
991     pFile->zClass = "local";
992   }
993   pFile->aJrnl = 0;
994   pFile->nJrnl = 0;
995   pFile->szPage = -1;
996   pFile->szDb = -1;
997   return SQLITE_OK;
998 }
999 
1000 /*
1001 ** Delete the file located at zPath. If the dirSync argument is true,
1002 ** ensure the file-system modifications are synced to disk before
1003 ** returning.
1004 */
1005 static int kvvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
1006   if( strcmp(zPath, "local-journal")==0 ){
1007     kvstorageDelete("local", "jrnl");
1008   }else
1009   if( strcmp(zPath, "session-journal")==0 ){
1010     kvstorageDelete("session", "jrnl");
1011   }
1012   return SQLITE_OK;
1013 }
1014 
1015 /*
1016 ** Test for access permissions. Return true if the requested permission
1017 ** is available, or false otherwise.
1018 */
1019 static int kvvfsAccess(
1020   sqlite3_vfs *pProtoVfs,
1021   const char *zPath,
1022   int flags,
1023   int *pResOut
1024 ){
1025   SQLITE_KV_LOG(("xAccess(\"%s\")\n", zPath));
1026   if( strcmp(zPath, "local-journal")==0 ){
1027     *pResOut = kvstorageRead("local", "jrnl", 0, 0)>0;
1028   }else
1029   if( strcmp(zPath, "session-journal")==0 ){
1030     *pResOut = kvstorageRead("session", "jrnl", 0, 0)>0;
1031   }else
1032   if( strcmp(zPath, "local")==0 ){
1033     *pResOut = kvstorageRead("local", "sz", 0, 0)>0;
1034   }else
1035   if( strcmp(zPath, "session")==0 ){
1036     *pResOut = kvstorageRead("session", "sz", 0, 0)>0;
1037   }else
1038   {
1039     *pResOut = 0;
1040   }
1041   SQLITE_KV_LOG(("xAccess returns %d\n",*pResOut));
1042   return SQLITE_OK;
1043 }
1044 
1045 /*
1046 ** Populate buffer zOut with the full canonical pathname corresponding
1047 ** to the pathname in zPath. zOut is guaranteed to point to a buffer
1048 ** of at least (INST_MAX_PATHNAME+1) bytes.
1049 */
1050 static int kvvfsFullPathname(
1051   sqlite3_vfs *pVfs,
1052   const char *zPath,
1053   int nOut,
1054   char *zOut
1055 ){
1056   size_t nPath;
1057 #ifdef SQLITE_OS_KV_ALWAYS_LOCAL
1058   zPath = "local";
1059 #endif
1060   nPath = strlen(zPath);
1061   SQLITE_KV_LOG(("xFullPathname(\"%s\")\n", zPath));
1062   if( nOut<nPath+1 ) nPath = nOut - 1;
1063   memcpy(zOut, zPath, nPath);
1064   zOut[nPath] = 0;
1065   return SQLITE_OK;
1066 }
1067 
1068 /*
1069 ** Open the dynamic library located at zPath and return a handle.
1070 */
1071 static void *kvvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
1072   return 0;
1073 }
1074 
1075 /*
1076 ** Populate the buffer pointed to by zBufOut with nByte bytes of
1077 ** random data.
1078 */
1079 static int kvvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
1080   memset(zBufOut, 0, nByte);
1081   return nByte;
1082 }
1083 
1084 /*
1085 ** Sleep for nMicro microseconds. Return the number of microseconds
1086 ** actually slept.
1087 */
1088 static int kvvfsSleep(sqlite3_vfs *pVfs, int nMicro){
1089   return SQLITE_OK;
1090 }
1091 
1092 /*
1093 ** Return the current time as a Julian Day number in *pTimeOut.
1094 */
1095 static int kvvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
1096   sqlite3_int64 i = 0;
1097   int rc;
1098   rc = kvvfsCurrentTimeInt64(0, &i);
1099   *pTimeOut = i/86400000.0;
1100   return rc;
1101 }
1102 #include <sys/time.h>
1103 static int kvvfsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
1104   static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
1105   struct timeval sNow;
1106   (void)gettimeofday(&sNow, 0);  /* Cannot fail given valid arguments */
1107   *pTimeOut = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
1108   return SQLITE_OK;
1109 }
1110 #endif /* SQLITE_OS_KV || SQLITE_OS_UNIX */
1111 
1112 #if SQLITE_OS_KV
1113 /*
1114 ** This routine is called initialize the KV-vfs as the default VFS.
1115 */
1116 int sqlite3_os_init(void){
1117   return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 1);
1118 }
1119 int sqlite3_os_end(void){
1120   return SQLITE_OK;
1121 }
1122 #endif /* SQLITE_OS_KV */
1123 
1124 #if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
1125 int sqlite3KvvfsInit(void){
1126   return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 0);
1127 }
1128 #endif
1129