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 static int kvstorageWrite(const char*, const char *zKey, const char *zData); 170 static int kvstorageDelete(const char*, const char *zKey); 171 static int kvstorageRead(const char*, const char *zKey, char *zBuf, int nBuf); 172 #define KVSTORAGE_KEY_SZ 32 173 174 /* Expand the key name with an appropriate prefix and put the result 175 ** zKeyOut[]. The zKeyOut[] buffer is assumed to hold at least 176 ** KVSTORAGE_KEY_SZ bytes. 177 */ 178 static void kvstorageMakeKey( 179 const char *zClass, 180 const char *zKeyIn, 181 char *zKeyOut 182 ){ 183 sqlite3_snprintf(KVSTORAGE_KEY_SZ, zKeyOut, "kvvfs-%s-%s", zClass, zKeyIn); 184 } 185 186 /* Write content into a key. zClass is the particular namespace of the 187 ** underlying key/value store to use - either "local" or "session". 188 ** 189 ** Both zKey and zData are zero-terminated pure text strings. 190 ** 191 ** Return the number of errors. 192 */ 193 static int kvstorageWrite( 194 const char *zClass, 195 const char *zKey, 196 const char *zData 197 ){ 198 FILE *fd; 199 char zXKey[KVSTORAGE_KEY_SZ]; 200 kvstorageMakeKey(zClass, zKey, zXKey); 201 fd = fopen(zXKey, "wb"); 202 if( fd ){ 203 SQLITE_KV_TRACE(("KVVFS-WRITE %-15s (%d) %.50s%s\n", zXKey, 204 (int)strlen(zData), zData, 205 strlen(zData)>50 ? "..." : "")); 206 fputs(zData, fd); 207 fclose(fd); 208 return 0; 209 }else{ 210 return 1; 211 } 212 } 213 214 /* Delete a key (with its corresponding data) from the key/value 215 ** namespace given by zClass. If the key does not previously exist, 216 ** this routine is a no-op. 217 */ 218 static int kvstorageDelete(const char *zClass, const char *zKey){ 219 char zXKey[KVSTORAGE_KEY_SZ]; 220 kvstorageMakeKey(zClass, zKey, zXKey); 221 unlink(zXKey); 222 SQLITE_KV_TRACE(("KVVFS-DELETE %-15s\n", zXKey)); 223 return 0; 224 } 225 226 /* Read the value associated with a zKey from the key/value namespace given 227 ** by zClass and put the text data associated with that key in the first 228 ** nBuf bytes of zBuf[]. The value might be truncated if zBuf is not large 229 ** enough to hold it all. The value put into zBuf must always be zero 230 ** terminated, even if it gets truncated because nBuf is not large enough. 231 ** 232 ** Return the total number of bytes in the data, without truncation, and 233 ** not counting the final zero terminator. Return -1 if the key does 234 ** not exist. 235 ** 236 ** If nBuf<=0 then this routine simply returns the size of the data without 237 ** actually reading it. 238 */ 239 static int kvstorageRead( 240 const char *zClass, 241 const char *zKey, 242 char *zBuf, 243 int nBuf 244 ){ 245 FILE *fd; 246 struct stat buf; 247 char zXKey[KVSTORAGE_KEY_SZ]; 248 kvstorageMakeKey(zClass, zKey, zXKey); 249 if( access(zXKey, R_OK)!=0 250 || stat(zXKey, &buf)!=0 251 || !S_ISREG(buf.st_mode) 252 ){ 253 SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey)); 254 return -1; 255 } 256 if( nBuf<=0 ){ 257 return (int)buf.st_size; 258 }else if( nBuf==1 ){ 259 zBuf[0] = 0; 260 SQLITE_KV_TRACE(("KVVFS-READ %-15s (%d)\n", zXKey, 261 (int)buf.st_size)); 262 return (int)buf.st_size; 263 } 264 if( nBuf > buf.st_size + 1 ){ 265 nBuf = buf.st_size + 1; 266 } 267 fd = fopen(zXKey, "rb"); 268 if( fd==0 ){ 269 SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey)); 270 return -1; 271 }else{ 272 sqlite3_int64 n = fread(zBuf, 1, nBuf-1, fd); 273 fclose(fd); 274 zBuf[n] = 0; 275 SQLITE_KV_TRACE(("KVVFS-READ %-15s (%lld) %.50s%s\n", zXKey, 276 n, zBuf, n>50 ? "..." : "")); 277 return (int)n; 278 } 279 } 280 281 /* 282 ** An internal level of indirection which enables us to replace the 283 ** kvvfs i/o methods with JavaScript implementations in WASM builds. 284 ** Maintenance reminder: if this struct changes in any way, the JSON 285 ** rendering of its structure must be updated in 286 ** sqlite3_wasm_enum_json(). There are no binary compatibility 287 ** concerns, so it does not need an iVersion member. This file is 288 ** necessarily always compiled together with sqlite3_wasm_enum_json(), 289 ** and JS code dynamically creates the mapping of members based on 290 ** that JSON description. 291 */ 292 typedef struct sqlite3_kvvfs_methods sqlite3_kvvfs_methods; 293 struct sqlite3_kvvfs_methods { 294 int (*xRead)(const char *zClass, const char *zKey, char *zBuf, int nBuf); 295 int (*xWrite)(const char *zClass, const char *zKey, const char *zData); 296 int (*xDelete)(const char *zClass, const char *zKey); 297 const int nKeySize; 298 }; 299 300 /* 301 ** This object holds the kvvfs I/O methods which may be swapped out 302 ** for JavaScript-side implementations in WASM builds. In such builds 303 ** it cannot be const, but in native builds it should be so that 304 ** the compiler can hopefully optimize this level of indirection out. 305 ** That said, kvvfs is intended primarily for use in WASM builds. 306 ** 307 ** Note that this is not explicitly flagged as static because the 308 ** amalgamation build will tag it with SQLITE_PRIVATE. 309 */ 310 #ifndef SQLITE_WASM 311 const 312 #endif 313 sqlite3_kvvfs_methods sqlite3KvvfsMethods = { 314 kvstorageRead, 315 kvstorageWrite, 316 kvstorageDelete, 317 KVSTORAGE_KEY_SZ 318 }; 319 320 /****** Utility subroutines ************************************************/ 321 322 /* 323 ** Encode binary into the text encoded used to persist on disk. 324 ** The output text is stored in aOut[], which must be at least 325 ** nData+1 bytes in length. 326 ** 327 ** Return the actual length of the encoded text, not counting the 328 ** zero terminator at the end. 329 ** 330 ** Encoding format 331 ** --------------- 332 ** 333 ** * Non-zero bytes are encoded as upper-case hexadecimal 334 ** 335 ** * A sequence of one or more zero-bytes that are not at the 336 ** beginning of the buffer are encoded as a little-endian 337 ** base-26 number using a..z. "a" means 0. "b" means 1, 338 ** "z" means 25. "ab" means 26. "ac" means 52. And so forth. 339 ** 340 ** * Because there is no overlap between the encoding characters 341 ** of hexadecimal and base-26 numbers, it is always clear where 342 ** one stops and the next begins. 343 */ 344 static int kvvfsEncode(const char *aData, int nData, char *aOut){ 345 int i, j; 346 const unsigned char *a = (const unsigned char*)aData; 347 for(i=j=0; i<nData; i++){ 348 unsigned char c = a[i]; 349 if( c!=0 ){ 350 aOut[j++] = "0123456789ABCDEF"[c>>4]; 351 aOut[j++] = "0123456789ABCDEF"[c&0xf]; 352 }else{ 353 /* A sequence of 1 or more zeros is stored as a little-endian 354 ** base-26 number using a..z as the digits. So one zero is "b". 355 ** Two zeros is "c". 25 zeros is "z", 26 zeros is "ab", 27 is "bb", 356 ** and so forth. 357 */ 358 int k; 359 for(k=1; i+k<nData && a[i+k]==0; k++){} 360 i += k-1; 361 while( k>0 ){ 362 aOut[j++] = 'a'+(k%26); 363 k /= 26; 364 } 365 } 366 } 367 aOut[j] = 0; 368 return j; 369 } 370 371 static const signed char kvvfsHexValue[256] = { 372 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 373 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 374 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 375 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, 376 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 377 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 378 -1, -1, -1, -1, -1, -1, -1, -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 381 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 382 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 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 }; 390 391 /* 392 ** Decode the text encoding back to binary. The binary content is 393 ** written into pOut, which must be at least nOut bytes in length. 394 ** 395 ** The return value is the number of bytes actually written into aOut[]. 396 */ 397 static int kvvfsDecode(const char *a, char *aOut, int nOut){ 398 int i, j; 399 int c; 400 const unsigned char *aIn = (const unsigned char*)a; 401 i = 0; 402 j = 0; 403 while( 1 ){ 404 c = kvvfsHexValue[aIn[i]]; 405 if( c<0 ){ 406 int n = 0; 407 int mult = 1; 408 c = aIn[i]; 409 if( c==0 ) break; 410 while( c>='a' && c<='z' ){ 411 n += (c - 'a')*mult; 412 mult *= 26; 413 c = aIn[++i]; 414 } 415 if( j+n>nOut ) return -1; 416 memset(&aOut[j], 0, n); 417 j += n; 418 c = aIn[i]; 419 if( c==0 ) break; 420 }else{ 421 aOut[j] = c<<4; 422 c = kvvfsHexValue[aIn[++i]]; 423 if( c<0 ) break; 424 aOut[j++] += c; 425 i++; 426 } 427 } 428 return j; 429 } 430 431 /* 432 ** Decode a complete journal file. Allocate space in pFile->aJrnl 433 ** and store the decoding there. Or leave pFile->aJrnl set to NULL 434 ** if an error is encountered. 435 ** 436 ** The first few characters of the text encoding will be a little-endian 437 ** base-26 number (digits a..z) that is the total number of bytes 438 ** in the decoded journal file image. This base-26 number is followed 439 ** by a single space, then the encoding of the journal. The space 440 ** separator is required to act as a terminator for the base-26 number. 441 */ 442 static void kvvfsDecodeJournal( 443 KVVfsFile *pFile, /* Store decoding in pFile->aJrnl */ 444 const char *zTxt, /* Text encoding. Zero-terminated */ 445 int nTxt /* Bytes in zTxt, excluding zero terminator */ 446 ){ 447 unsigned int n = 0; 448 int c, i, mult; 449 i = 0; 450 mult = 1; 451 while( (c = zTxt[i++])>='a' && c<='z' ){ 452 n += (zTxt[i] - 'a')*mult; 453 mult *= 26; 454 } 455 sqlite3_free(pFile->aJrnl); 456 pFile->aJrnl = sqlite3_malloc64( n ); 457 if( pFile->aJrnl==0 ){ 458 pFile->nJrnl = 0; 459 return; 460 } 461 pFile->nJrnl = n; 462 n = kvvfsDecode(zTxt+i, pFile->aJrnl, pFile->nJrnl); 463 if( n<pFile->nJrnl ){ 464 sqlite3_free(pFile->aJrnl); 465 pFile->aJrnl = 0; 466 pFile->nJrnl = 0; 467 } 468 } 469 470 /* 471 ** Read or write the "sz" element, containing the database file size. 472 */ 473 static sqlite3_int64 kvvfsReadFileSize(KVVfsFile *pFile){ 474 char zData[50]; 475 zData[0] = 0; 476 sqlite3KvvfsMethods.xRead(pFile->zClass, "sz", zData, sizeof(zData)-1); 477 return strtoll(zData, 0, 0); 478 } 479 static int kvvfsWriteFileSize(KVVfsFile *pFile, sqlite3_int64 sz){ 480 char zData[50]; 481 sqlite3_snprintf(sizeof(zData), zData, "%lld", sz); 482 return sqlite3KvvfsMethods.xWrite(pFile->zClass, "sz", zData); 483 } 484 485 /****** sqlite3_io_methods methods ******************************************/ 486 487 /* 488 ** Close an kvvfs-file. 489 */ 490 static int kvvfsClose(sqlite3_file *pProtoFile){ 491 KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 492 493 SQLITE_KV_LOG(("xClose %s %s\n", pFile->zClass, 494 pFile->isJournal ? "journal" : "db")); 495 sqlite3_free(pFile->aJrnl); 496 return SQLITE_OK; 497 } 498 499 /* 500 ** Read from the -journal file. 501 */ 502 static int kvvfsReadJrnl( 503 sqlite3_file *pProtoFile, 504 void *zBuf, 505 int iAmt, 506 sqlite_int64 iOfst 507 ){ 508 KVVfsFile *pFile = (KVVfsFile*)pProtoFile; 509 assert( pFile->isJournal ); 510 SQLITE_KV_LOG(("xRead('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst)); 511 if( pFile->aJrnl==0 ){ 512 int szTxt = kvstorageRead(pFile->zClass, "jrnl", 0, 0); 513 char *aTxt; 514 if( szTxt<=4 ){ 515 return SQLITE_IOERR; 516 } 517 aTxt = sqlite3_malloc64( szTxt+1 ); 518 if( aTxt==0 ) return SQLITE_NOMEM; 519 kvstorageRead(pFile->zClass, "jrnl", aTxt, szTxt+1); 520 kvvfsDecodeJournal(pFile, aTxt, szTxt); 521 sqlite3_free(aTxt); 522 if( pFile->aJrnl==0 ) return SQLITE_IOERR; 523 } 524 if( iOfst+iAmt>pFile->nJrnl ){ 525 return SQLITE_IOERR_SHORT_READ; 526 } 527 memcpy(zBuf, pFile->aJrnl+iOfst, iAmt); 528 return SQLITE_OK; 529 } 530 531 /* 532 ** Read from the database file. 533 */ 534 static int kvvfsReadDb( 535 sqlite3_file *pProtoFile, 536 void *zBuf, 537 int iAmt, 538 sqlite_int64 iOfst 539 ){ 540 KVVfsFile *pFile = (KVVfsFile*)pProtoFile; 541 unsigned int pgno; 542 int got, n; 543 char zKey[30]; 544 char aData[133073]; 545 assert( iOfst>=0 ); 546 assert( iAmt>=0 ); 547 SQLITE_KV_LOG(("xRead('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst)); 548 if( iOfst+iAmt>=512 ){ 549 if( (iOfst % iAmt)!=0 ){ 550 return SQLITE_IOERR_READ; 551 } 552 if( (iAmt & (iAmt-1))!=0 || iAmt<512 || iAmt>65536 ){ 553 return SQLITE_IOERR_READ; 554 } 555 pFile->szPage = iAmt; 556 pgno = 1 + iOfst/iAmt; 557 }else{ 558 pgno = 1; 559 } 560 sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno); 561 got = sqlite3KvvfsMethods.xRead(pFile->zClass, zKey, aData, sizeof(aData)-1); 562 if( got<0 ){ 563 n = 0; 564 }else{ 565 aData[got] = 0; 566 if( iOfst+iAmt<512 ){ 567 int k = iOfst+iAmt; 568 aData[k*2] = 0; 569 n = kvvfsDecode(aData, &aData[2000], sizeof(aData)-2000); 570 if( n>=iOfst+iAmt ){ 571 memcpy(zBuf, &aData[2000+iOfst], iAmt); 572 n = iAmt; 573 }else{ 574 n = 0; 575 } 576 }else{ 577 n = kvvfsDecode(aData, zBuf, iAmt); 578 } 579 } 580 if( n<iAmt ){ 581 memset(zBuf+n, 0, iAmt-n); 582 return SQLITE_IOERR_SHORT_READ; 583 } 584 return SQLITE_OK; 585 } 586 587 588 /* 589 ** Write into the -journal file. 590 */ 591 static int kvvfsWriteJrnl( 592 sqlite3_file *pProtoFile, 593 const void *zBuf, 594 int iAmt, 595 sqlite_int64 iOfst 596 ){ 597 KVVfsFile *pFile = (KVVfsFile*)pProtoFile; 598 sqlite3_int64 iEnd = iOfst+iAmt; 599 SQLITE_KV_LOG(("xWrite('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst)); 600 if( iEnd>=0x10000000 ) return SQLITE_FULL; 601 if( pFile->aJrnl==0 || pFile->nJrnl<iEnd ){ 602 char *aNew = sqlite3_realloc(pFile->aJrnl, iEnd); 603 if( aNew==0 ){ 604 return SQLITE_IOERR_NOMEM; 605 } 606 pFile->aJrnl = aNew; 607 if( pFile->nJrnl<iOfst ){ 608 memset(pFile->aJrnl+pFile->nJrnl, 0, iOfst-pFile->nJrnl); 609 } 610 pFile->nJrnl = iEnd; 611 } 612 memcpy(pFile->aJrnl+iOfst, zBuf, iAmt); 613 return SQLITE_OK; 614 } 615 616 /* 617 ** Write into the database file. 618 */ 619 static int kvvfsWriteDb( 620 sqlite3_file *pProtoFile, 621 const void *zBuf, 622 int iAmt, 623 sqlite_int64 iOfst 624 ){ 625 KVVfsFile *pFile = (KVVfsFile*)pProtoFile; 626 unsigned int pgno; 627 char zKey[30]; 628 char aData[131073]; 629 SQLITE_KV_LOG(("xWrite('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst)); 630 assert( iAmt>=512 && iAmt<=65536 ); 631 assert( (iAmt & (iAmt-1))==0 ); 632 assert( pFile->szPage<0 || pFile->szPage==iAmt ); 633 pFile->szPage = iAmt; 634 pgno = 1 + iOfst/iAmt; 635 sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno); 636 kvvfsEncode(zBuf, iAmt, aData); 637 if( sqlite3KvvfsMethods.xWrite(pFile->zClass, zKey, aData) ){ 638 return SQLITE_IOERR; 639 } 640 if( iOfst+iAmt > pFile->szDb ){ 641 pFile->szDb = iOfst + iAmt; 642 } 643 return SQLITE_OK; 644 } 645 646 /* 647 ** Truncate an kvvfs-file. 648 */ 649 static int kvvfsTruncateJrnl(sqlite3_file *pProtoFile, sqlite_int64 size){ 650 KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 651 SQLITE_KV_LOG(("xTruncate('%s-journal',%lld)\n", pFile->zClass, size)); 652 assert( size==0 ); 653 sqlite3KvvfsMethods.xDelete(pFile->zClass, "jrnl"); 654 sqlite3_free(pFile->aJrnl); 655 pFile->aJrnl = 0; 656 pFile->nJrnl = 0; 657 return SQLITE_OK; 658 } 659 static int kvvfsTruncateDb(sqlite3_file *pProtoFile, sqlite_int64 size){ 660 KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 661 if( pFile->szDb>size 662 && pFile->szPage>0 663 && (size % pFile->szPage)==0 664 ){ 665 char zKey[50]; 666 unsigned int pgno, pgnoMax; 667 SQLITE_KV_LOG(("xTruncate('%s-db',%lld)\n", pFile->zClass, size)); 668 pgno = 1 + size/pFile->szPage; 669 pgnoMax = 2 + pFile->szDb/pFile->szPage; 670 while( pgno<=pgnoMax ){ 671 sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno); 672 sqlite3KvvfsMethods.xDelete(pFile->zClass, zKey); 673 pgno++; 674 } 675 pFile->szDb = size; 676 return kvvfsWriteFileSize(pFile, size) ? SQLITE_IOERR : SQLITE_OK; 677 } 678 return SQLITE_IOERR; 679 } 680 681 /* 682 ** Sync an kvvfs-file. 683 */ 684 static int kvvfsSyncJrnl(sqlite3_file *pProtoFile, int flags){ 685 int i, n; 686 KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 687 char *zOut; 688 SQLITE_KV_LOG(("xSync('%s-journal')\n", pFile->zClass)); 689 if( pFile->nJrnl<=0 ){ 690 return kvvfsTruncateJrnl(pProtoFile, 0); 691 } 692 zOut = sqlite3_malloc64( pFile->nJrnl*2 + 50 ); 693 if( zOut==0 ){ 694 return SQLITE_IOERR_NOMEM; 695 } 696 n = pFile->nJrnl; 697 i = 0; 698 do{ 699 zOut[i++] = 'a' + (n%26); 700 n /= 26; 701 }while( n>0 ); 702 zOut[i++] = ' '; 703 kvvfsEncode(pFile->aJrnl, pFile->nJrnl, &zOut[i]); 704 i = sqlite3KvvfsMethods.xWrite(pFile->zClass, "jrnl", zOut); 705 sqlite3_free(zOut); 706 return i ? SQLITE_IOERR : SQLITE_OK; 707 } 708 static int kvvfsSyncDb(sqlite3_file *pProtoFile, int flags){ 709 return SQLITE_OK; 710 } 711 712 /* 713 ** Return the current file-size of an kvvfs-file. 714 */ 715 static int kvvfsFileSizeJrnl(sqlite3_file *pProtoFile, sqlite_int64 *pSize){ 716 KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 717 SQLITE_KV_LOG(("xFileSize('%s-journal')\n", pFile->zClass)); 718 *pSize = pFile->nJrnl; 719 return SQLITE_OK; 720 } 721 static int kvvfsFileSizeDb(sqlite3_file *pProtoFile, sqlite_int64 *pSize){ 722 KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 723 SQLITE_KV_LOG(("xFileSize('%s-db')\n", pFile->zClass)); 724 if( pFile->szDb>=0 ){ 725 *pSize = pFile->szDb; 726 }else{ 727 *pSize = kvvfsReadFileSize(pFile); 728 } 729 return SQLITE_OK; 730 } 731 732 /* 733 ** Lock an kvvfs-file. 734 */ 735 static int kvvfsLock(sqlite3_file *pProtoFile, int eLock){ 736 KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 737 assert( !pFile->isJournal ); 738 SQLITE_KV_LOG(("xLock(%s,%d)\n", pFile->zClass, eLock)); 739 740 if( eLock!=SQLITE_LOCK_NONE ){ 741 pFile->szDb = kvvfsReadFileSize(pFile); 742 } 743 return SQLITE_OK; 744 } 745 746 /* 747 ** Unlock an kvvfs-file. 748 */ 749 static int kvvfsUnlock(sqlite3_file *pProtoFile, int eLock){ 750 KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 751 assert( !pFile->isJournal ); 752 SQLITE_KV_LOG(("xUnlock(%s,%d)\n", pFile->zClass, eLock)); 753 if( eLock==SQLITE_LOCK_NONE ){ 754 pFile->szDb = -1; 755 } 756 return SQLITE_OK; 757 } 758 759 /* 760 ** Check if another file-handle holds a RESERVED lock on an kvvfs-file. 761 */ 762 static int kvvfsCheckReservedLock(sqlite3_file *pProtoFile, int *pResOut){ 763 SQLITE_KV_LOG(("xCheckReservedLock\n")); 764 *pResOut = 0; 765 return SQLITE_OK; 766 } 767 768 /* 769 ** File control method. For custom operations on an kvvfs-file. 770 */ 771 static int kvvfsFileControlJrnl(sqlite3_file *pProtoFile, int op, void *pArg){ 772 SQLITE_KV_LOG(("xFileControl(%d) on journal\n", op)); 773 return SQLITE_NOTFOUND; 774 } 775 static int kvvfsFileControlDb(sqlite3_file *pProtoFile, int op, void *pArg){ 776 SQLITE_KV_LOG(("xFileControl(%d) on database\n", op)); 777 if( op==SQLITE_FCNTL_SYNC ){ 778 KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 779 int rc = SQLITE_OK; 780 SQLITE_KV_LOG(("xSync('%s-db')\n", pFile->zClass)); 781 if( pFile->szDb>0 && 0!=kvvfsWriteFileSize(pFile, pFile->szDb) ){ 782 rc = SQLITE_IOERR; 783 } 784 return rc; 785 } 786 return SQLITE_NOTFOUND; 787 } 788 789 /* 790 ** Return the sector-size in bytes for an kvvfs-file. 791 */ 792 static int kvvfsSectorSize(sqlite3_file *pFile){ 793 return 512; 794 } 795 796 /* 797 ** Return the device characteristic flags supported by an kvvfs-file. 798 */ 799 static int kvvfsDeviceCharacteristics(sqlite3_file *pProtoFile){ 800 return 0; 801 } 802 803 /****** sqlite3_vfs methods *************************************************/ 804 805 /* 806 ** Open an kvvfs file handle. 807 */ 808 static int kvvfsOpen( 809 sqlite3_vfs *pProtoVfs, 810 const char *zName, 811 sqlite3_file *pProtoFile, 812 int flags, 813 int *pOutFlags 814 ){ 815 KVVfsFile *pFile = (KVVfsFile*)pProtoFile; 816 if( zName==0 ) zName = ""; 817 SQLITE_KV_LOG(("xOpen(\"%s\")\n", zName)); 818 if( strcmp(zName, "local")==0 819 || strcmp(zName, "session")==0 820 ){ 821 pFile->isJournal = 0; 822 pFile->base.pMethods = &kvvfs_db_io_methods; 823 }else 824 if( strcmp(zName, "local-journal")==0 825 || strcmp(zName, "session-journal")==0 826 ){ 827 pFile->isJournal = 1; 828 pFile->base.pMethods = &kvvfs_jrnl_io_methods; 829 }else{ 830 return SQLITE_CANTOPEN; 831 } 832 if( zName[0]=='s' ){ 833 pFile->zClass = "session"; 834 }else{ 835 pFile->zClass = "local"; 836 } 837 pFile->aJrnl = 0; 838 pFile->nJrnl = 0; 839 pFile->szPage = -1; 840 pFile->szDb = -1; 841 return SQLITE_OK; 842 } 843 844 /* 845 ** Delete the file located at zPath. If the dirSync argument is true, 846 ** ensure the file-system modifications are synced to disk before 847 ** returning. 848 */ 849 static int kvvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ 850 if( strcmp(zPath, "local-journal")==0 ){ 851 sqlite3KvvfsMethods.xDelete("local", "jrnl"); 852 }else 853 if( strcmp(zPath, "session-journal")==0 ){ 854 sqlite3KvvfsMethods.xDelete("session", "jrnl"); 855 } 856 return SQLITE_OK; 857 } 858 859 /* 860 ** Test for access permissions. Return true if the requested permission 861 ** is available, or false otherwise. 862 */ 863 static int kvvfsAccess( 864 sqlite3_vfs *pProtoVfs, 865 const char *zPath, 866 int flags, 867 int *pResOut 868 ){ 869 SQLITE_KV_LOG(("xAccess(\"%s\")\n", zPath)); 870 if( strcmp(zPath, "local-journal")==0 ){ 871 *pResOut = sqlite3KvvfsMethods.xRead("local", "jrnl", 0, 0)>0; 872 }else 873 if( strcmp(zPath, "session-journal")==0 ){ 874 *pResOut = sqlite3KvvfsMethods.xRead("session", "jrnl", 0, 0)>0; 875 }else 876 if( strcmp(zPath, "local")==0 ){ 877 *pResOut = sqlite3KvvfsMethods.xRead("local", "sz", 0, 0)>0; 878 }else 879 if( strcmp(zPath, "session")==0 ){ 880 *pResOut = sqlite3KvvfsMethods.xRead("session", "sz", 0, 0)>0; 881 }else 882 { 883 *pResOut = 0; 884 } 885 SQLITE_KV_LOG(("xAccess returns %d\n",*pResOut)); 886 return SQLITE_OK; 887 } 888 889 /* 890 ** Populate buffer zOut with the full canonical pathname corresponding 891 ** to the pathname in zPath. zOut is guaranteed to point to a buffer 892 ** of at least (INST_MAX_PATHNAME+1) bytes. 893 */ 894 static int kvvfsFullPathname( 895 sqlite3_vfs *pVfs, 896 const char *zPath, 897 int nOut, 898 char *zOut 899 ){ 900 size_t nPath; 901 #ifdef SQLITE_OS_KV_ALWAYS_LOCAL 902 zPath = "local"; 903 #endif 904 nPath = strlen(zPath); 905 SQLITE_KV_LOG(("xFullPathname(\"%s\")\n", zPath)); 906 if( nOut<nPath+1 ) nPath = nOut - 1; 907 memcpy(zOut, zPath, nPath); 908 zOut[nPath] = 0; 909 return SQLITE_OK; 910 } 911 912 /* 913 ** Open the dynamic library located at zPath and return a handle. 914 */ 915 static void *kvvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){ 916 return 0; 917 } 918 919 /* 920 ** Populate the buffer pointed to by zBufOut with nByte bytes of 921 ** random data. 922 */ 923 static int kvvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ 924 memset(zBufOut, 0, nByte); 925 return nByte; 926 } 927 928 /* 929 ** Sleep for nMicro microseconds. Return the number of microseconds 930 ** actually slept. 931 */ 932 static int kvvfsSleep(sqlite3_vfs *pVfs, int nMicro){ 933 return SQLITE_OK; 934 } 935 936 /* 937 ** Return the current time as a Julian Day number in *pTimeOut. 938 */ 939 static int kvvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ 940 sqlite3_int64 i = 0; 941 int rc; 942 rc = kvvfsCurrentTimeInt64(0, &i); 943 *pTimeOut = i/86400000.0; 944 return rc; 945 } 946 #include <sys/time.h> 947 static int kvvfsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){ 948 static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; 949 struct timeval sNow; 950 (void)gettimeofday(&sNow, 0); /* Cannot fail given valid arguments */ 951 *pTimeOut = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000; 952 return SQLITE_OK; 953 } 954 #endif /* SQLITE_OS_KV || SQLITE_OS_UNIX */ 955 956 #if SQLITE_OS_KV 957 /* 958 ** This routine is called initialize the KV-vfs as the default VFS. 959 */ 960 int sqlite3_os_init(void){ 961 return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 1); 962 } 963 int sqlite3_os_end(void){ 964 return SQLITE_OK; 965 } 966 #endif /* SQLITE_OS_KV */ 967 968 #if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL) 969 int sqlite3KvvfsInit(void){ 970 return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 0); 971 } 972 #endif 973