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 pgno = 1 + iOfst/iAmt; 633 sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno); 634 kvvfsEncode(zBuf, iAmt, aData); 635 if( sqlite3KvvfsMethods.xWrite(pFile->zClass, zKey, aData) ){ 636 return SQLITE_IOERR; 637 } 638 if( iOfst+iAmt > pFile->szDb ){ 639 pFile->szDb = iOfst + iAmt; 640 } 641 return SQLITE_OK; 642 } 643 644 /* 645 ** Truncate an kvvfs-file. 646 */ 647 static int kvvfsTruncateJrnl(sqlite3_file *pProtoFile, sqlite_int64 size){ 648 KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 649 SQLITE_KV_LOG(("xTruncate('%s-journal',%lld)\n", pFile->zClass, size)); 650 assert( size==0 ); 651 sqlite3KvvfsMethods.xDelete(pFile->zClass, "jrnl"); 652 sqlite3_free(pFile->aJrnl); 653 pFile->aJrnl = 0; 654 pFile->nJrnl = 0; 655 return SQLITE_OK; 656 } 657 static int kvvfsTruncateDb(sqlite3_file *pProtoFile, sqlite_int64 size){ 658 KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 659 if( pFile->szDb>size 660 && pFile->szPage>0 661 && (size % pFile->szPage)==0 662 ){ 663 char zKey[50]; 664 unsigned int pgno, pgnoMax; 665 SQLITE_KV_LOG(("xTruncate('%s-db',%lld)\n", pFile->zClass, size)); 666 pgno = 1 + size/pFile->szPage; 667 pgnoMax = 2 + pFile->szDb/pFile->szPage; 668 while( pgno<=pgnoMax ){ 669 sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno); 670 sqlite3KvvfsMethods.xDelete(pFile->zClass, zKey); 671 pgno++; 672 } 673 pFile->szDb = size; 674 return kvvfsWriteFileSize(pFile, size) ? SQLITE_IOERR : SQLITE_OK; 675 } 676 return SQLITE_IOERR; 677 } 678 679 /* 680 ** Sync an kvvfs-file. 681 */ 682 static int kvvfsSyncJrnl(sqlite3_file *pProtoFile, int flags){ 683 int i, n; 684 KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 685 char *zOut; 686 SQLITE_KV_LOG(("xSync('%s-journal')\n", pFile->zClass)); 687 if( pFile->nJrnl<=0 ){ 688 return kvvfsTruncateJrnl(pProtoFile, 0); 689 } 690 zOut = sqlite3_malloc64( pFile->nJrnl*2 + 50 ); 691 if( zOut==0 ){ 692 return SQLITE_IOERR_NOMEM; 693 } 694 n = pFile->nJrnl; 695 i = 0; 696 do{ 697 zOut[i++] = 'a' + (n%26); 698 n /= 26; 699 }while( n>0 ); 700 zOut[i++] = ' '; 701 kvvfsEncode(pFile->aJrnl, pFile->nJrnl, &zOut[i]); 702 i = sqlite3KvvfsMethods.xWrite(pFile->zClass, "jrnl", zOut); 703 sqlite3_free(zOut); 704 return i ? SQLITE_IOERR : SQLITE_OK; 705 } 706 static int kvvfsSyncDb(sqlite3_file *pProtoFile, int flags){ 707 return SQLITE_OK; 708 } 709 710 /* 711 ** Return the current file-size of an kvvfs-file. 712 */ 713 static int kvvfsFileSizeJrnl(sqlite3_file *pProtoFile, sqlite_int64 *pSize){ 714 KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 715 SQLITE_KV_LOG(("xFileSize('%s-journal')\n", pFile->zClass)); 716 *pSize = pFile->nJrnl; 717 return SQLITE_OK; 718 } 719 static int kvvfsFileSizeDb(sqlite3_file *pProtoFile, sqlite_int64 *pSize){ 720 KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 721 SQLITE_KV_LOG(("xFileSize('%s-db')\n", pFile->zClass)); 722 if( pFile->szDb>=0 ){ 723 *pSize = pFile->szDb; 724 }else{ 725 *pSize = kvvfsReadFileSize(pFile); 726 } 727 return SQLITE_OK; 728 } 729 730 /* 731 ** Lock an kvvfs-file. 732 */ 733 static int kvvfsLock(sqlite3_file *pProtoFile, int eLock){ 734 KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 735 assert( !pFile->isJournal ); 736 SQLITE_KV_LOG(("xLock(%s,%d)\n", pFile->zClass, eLock)); 737 738 if( eLock!=SQLITE_LOCK_NONE ){ 739 pFile->szDb = kvvfsReadFileSize(pFile); 740 } 741 return SQLITE_OK; 742 } 743 744 /* 745 ** Unlock an kvvfs-file. 746 */ 747 static int kvvfsUnlock(sqlite3_file *pProtoFile, int eLock){ 748 KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 749 assert( !pFile->isJournal ); 750 SQLITE_KV_LOG(("xUnlock(%s,%d)\n", pFile->zClass, eLock)); 751 if( eLock==SQLITE_LOCK_NONE ){ 752 pFile->szDb = -1; 753 } 754 return SQLITE_OK; 755 } 756 757 /* 758 ** Check if another file-handle holds a RESERVED lock on an kvvfs-file. 759 */ 760 static int kvvfsCheckReservedLock(sqlite3_file *pProtoFile, int *pResOut){ 761 SQLITE_KV_LOG(("xCheckReservedLock\n")); 762 *pResOut = 0; 763 return SQLITE_OK; 764 } 765 766 /* 767 ** File control method. For custom operations on an kvvfs-file. 768 */ 769 static int kvvfsFileControlJrnl(sqlite3_file *pProtoFile, int op, void *pArg){ 770 SQLITE_KV_LOG(("xFileControl(%d) on journal\n", op)); 771 return SQLITE_NOTFOUND; 772 } 773 static int kvvfsFileControlDb(sqlite3_file *pProtoFile, int op, void *pArg){ 774 SQLITE_KV_LOG(("xFileControl(%d) on database\n", op)); 775 if( op==SQLITE_FCNTL_SYNC ){ 776 KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 777 int rc = SQLITE_OK; 778 SQLITE_KV_LOG(("xSync('%s-db')\n", pFile->zClass)); 779 if( pFile->szDb>0 && 0!=kvvfsWriteFileSize(pFile, pFile->szDb) ){ 780 rc = SQLITE_IOERR; 781 } 782 return rc; 783 } 784 return SQLITE_NOTFOUND; 785 } 786 787 /* 788 ** Return the sector-size in bytes for an kvvfs-file. 789 */ 790 static int kvvfsSectorSize(sqlite3_file *pFile){ 791 return 512; 792 } 793 794 /* 795 ** Return the device characteristic flags supported by an kvvfs-file. 796 */ 797 static int kvvfsDeviceCharacteristics(sqlite3_file *pProtoFile){ 798 return 0; 799 } 800 801 /****** sqlite3_vfs methods *************************************************/ 802 803 /* 804 ** Open an kvvfs file handle. 805 */ 806 static int kvvfsOpen( 807 sqlite3_vfs *pProtoVfs, 808 const char *zName, 809 sqlite3_file *pProtoFile, 810 int flags, 811 int *pOutFlags 812 ){ 813 KVVfsFile *pFile = (KVVfsFile*)pProtoFile; 814 SQLITE_KV_LOG(("xOpen(\"%s\")\n", zName)); 815 if( strcmp(zName, "local")==0 816 || strcmp(zName, "session")==0 817 ){ 818 pFile->isJournal = 0; 819 pFile->base.pMethods = &kvvfs_db_io_methods; 820 }else 821 if( strcmp(zName, "local-journal")==0 822 || strcmp(zName, "session-journal")==0 823 ){ 824 pFile->isJournal = 1; 825 pFile->base.pMethods = &kvvfs_jrnl_io_methods; 826 }else{ 827 return SQLITE_CANTOPEN; 828 } 829 if( zName[0]=='s' ){ 830 pFile->zClass = "session"; 831 }else{ 832 pFile->zClass = "local"; 833 } 834 pFile->aJrnl = 0; 835 pFile->nJrnl = 0; 836 pFile->szPage = -1; 837 pFile->szDb = -1; 838 return SQLITE_OK; 839 } 840 841 /* 842 ** Delete the file located at zPath. If the dirSync argument is true, 843 ** ensure the file-system modifications are synced to disk before 844 ** returning. 845 */ 846 static int kvvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ 847 if( strcmp(zPath, "local-journal")==0 ){ 848 sqlite3KvvfsMethods.xDelete("local", "jrnl"); 849 }else 850 if( strcmp(zPath, "session-journal")==0 ){ 851 sqlite3KvvfsMethods.xDelete("session", "jrnl"); 852 } 853 return SQLITE_OK; 854 } 855 856 /* 857 ** Test for access permissions. Return true if the requested permission 858 ** is available, or false otherwise. 859 */ 860 static int kvvfsAccess( 861 sqlite3_vfs *pProtoVfs, 862 const char *zPath, 863 int flags, 864 int *pResOut 865 ){ 866 SQLITE_KV_LOG(("xAccess(\"%s\")\n", zPath)); 867 if( strcmp(zPath, "local-journal")==0 ){ 868 *pResOut = sqlite3KvvfsMethods.xRead("local", "jrnl", 0, 0)>0; 869 }else 870 if( strcmp(zPath, "session-journal")==0 ){ 871 *pResOut = sqlite3KvvfsMethods.xRead("session", "jrnl", 0, 0)>0; 872 }else 873 if( strcmp(zPath, "local")==0 ){ 874 *pResOut = sqlite3KvvfsMethods.xRead("local", "sz", 0, 0)>0; 875 }else 876 if( strcmp(zPath, "session")==0 ){ 877 *pResOut = sqlite3KvvfsMethods.xRead("session", "sz", 0, 0)>0; 878 }else 879 { 880 *pResOut = 0; 881 } 882 SQLITE_KV_LOG(("xAccess returns %d\n",*pResOut)); 883 return SQLITE_OK; 884 } 885 886 /* 887 ** Populate buffer zOut with the full canonical pathname corresponding 888 ** to the pathname in zPath. zOut is guaranteed to point to a buffer 889 ** of at least (INST_MAX_PATHNAME+1) bytes. 890 */ 891 static int kvvfsFullPathname( 892 sqlite3_vfs *pVfs, 893 const char *zPath, 894 int nOut, 895 char *zOut 896 ){ 897 size_t nPath; 898 #ifdef SQLITE_OS_KV_ALWAYS_LOCAL 899 zPath = "local"; 900 #endif 901 nPath = strlen(zPath); 902 SQLITE_KV_LOG(("xFullPathname(\"%s\")\n", zPath)); 903 if( nOut<nPath+1 ) nPath = nOut - 1; 904 memcpy(zOut, zPath, nPath); 905 zOut[nPath] = 0; 906 return SQLITE_OK; 907 } 908 909 /* 910 ** Open the dynamic library located at zPath and return a handle. 911 */ 912 static void *kvvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){ 913 return 0; 914 } 915 916 /* 917 ** Populate the buffer pointed to by zBufOut with nByte bytes of 918 ** random data. 919 */ 920 static int kvvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ 921 memset(zBufOut, 0, nByte); 922 return nByte; 923 } 924 925 /* 926 ** Sleep for nMicro microseconds. Return the number of microseconds 927 ** actually slept. 928 */ 929 static int kvvfsSleep(sqlite3_vfs *pVfs, int nMicro){ 930 return SQLITE_OK; 931 } 932 933 /* 934 ** Return the current time as a Julian Day number in *pTimeOut. 935 */ 936 static int kvvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ 937 sqlite3_int64 i = 0; 938 int rc; 939 rc = kvvfsCurrentTimeInt64(0, &i); 940 *pTimeOut = i/86400000.0; 941 return rc; 942 } 943 #include <sys/time.h> 944 static int kvvfsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){ 945 static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; 946 struct timeval sNow; 947 (void)gettimeofday(&sNow, 0); /* Cannot fail given valid arguments */ 948 *pTimeOut = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000; 949 return SQLITE_OK; 950 } 951 #endif /* SQLITE_OS_KV || SQLITE_OS_UNIX */ 952 953 #if SQLITE_OS_KV 954 /* 955 ** This routine is called initialize the KV-vfs as the default VFS. 956 */ 957 int sqlite3_os_init(void){ 958 return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 1); 959 } 960 int sqlite3_os_end(void){ 961 return SQLITE_OK; 962 } 963 #endif /* SQLITE_OS_KV */ 964 965 #if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL) 966 int sqlite3KvvfsInit(void){ 967 return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 0); 968 } 969 #endif 970