1*7585f49aSdrh /* 2*7585f49aSdrh ** 2022-09-06 3*7585f49aSdrh ** 4*7585f49aSdrh ** The author disclaims copyright to this source code. In place of 5*7585f49aSdrh ** a legal notice, here is a blessing: 6*7585f49aSdrh ** 7*7585f49aSdrh ** May you do good and not evil. 8*7585f49aSdrh ** May you find forgiveness for yourself and forgive others. 9*7585f49aSdrh ** May you share freely, never taking more than you give. 10*7585f49aSdrh ** 11*7585f49aSdrh ****************************************************************************** 12*7585f49aSdrh ** 13*7585f49aSdrh ** This file contains an experimental VFS layer that operates on a 14*7585f49aSdrh ** Key/Value storage engine where both keys and values must be pure 15*7585f49aSdrh ** text. 16*7585f49aSdrh */ 17*7585f49aSdrh #include <sqliteInt.h> 18*7585f49aSdrh #if SQLITE_OS_KV 19*7585f49aSdrh 20*7585f49aSdrh /***************************************************************************** 21*7585f49aSdrh ** Debugging logic 22*7585f49aSdrh */ 23*7585f49aSdrh 24*7585f49aSdrh /* SQLITE_KV_TRACE() is used for tracing calls to kvstorage routines. */ 25*7585f49aSdrh #if 0 26*7585f49aSdrh #define SQLITE_KV_TRACE(X) printf X; 27*7585f49aSdrh #else 28*7585f49aSdrh #define SQLITE_KV_TRACE(X) 29*7585f49aSdrh #endif 30*7585f49aSdrh 31*7585f49aSdrh /* SQLITE_KV_LOG() is used for tracing calls to the VFS interface */ 32*7585f49aSdrh #if 0 33*7585f49aSdrh #define SQLITE_KV_LOG(X) printf X; 34*7585f49aSdrh #else 35*7585f49aSdrh #define SQLITE_KV_LOG(X) 36*7585f49aSdrh #endif 37*7585f49aSdrh 38*7585f49aSdrh 39*7585f49aSdrh /* 40*7585f49aSdrh ** Forward declaration of objects used by this VFS implementation 41*7585f49aSdrh */ 42*7585f49aSdrh typedef struct KVVfsFile KVVfsFile; 43*7585f49aSdrh 44*7585f49aSdrh /* A single open file. There are only two files represented by this 45*7585f49aSdrh ** VFS - the database and the rollback journal. 46*7585f49aSdrh */ 47*7585f49aSdrh struct KVVfsFile { 48*7585f49aSdrh sqlite3_file base; /* IO methods */ 49*7585f49aSdrh const char *zClass; /* Storage class */ 50*7585f49aSdrh int isJournal; /* True if this is a journal file */ 51*7585f49aSdrh unsigned int nJrnl; /* Space allocated for aJrnl[] */ 52*7585f49aSdrh char *aJrnl; /* Journal content */ 53*7585f49aSdrh int szPage; /* Last known page size */ 54*7585f49aSdrh sqlite3_int64 szDb; /* Database file size. -1 means unknown */ 55*7585f49aSdrh }; 56*7585f49aSdrh 57*7585f49aSdrh /* 58*7585f49aSdrh ** Methods for KVVfsFile 59*7585f49aSdrh */ 60*7585f49aSdrh static int kvvfsClose(sqlite3_file*); 61*7585f49aSdrh static int kvvfsReadDb(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); 62*7585f49aSdrh static int kvvfsReadJrnl(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); 63*7585f49aSdrh static int kvvfsWriteDb(sqlite3_file*,const void*,int iAmt, sqlite3_int64); 64*7585f49aSdrh static int kvvfsWriteJrnl(sqlite3_file*,const void*,int iAmt, sqlite3_int64); 65*7585f49aSdrh static int kvvfsTruncateDb(sqlite3_file*, sqlite3_int64 size); 66*7585f49aSdrh static int kvvfsTruncateJrnl(sqlite3_file*, sqlite3_int64 size); 67*7585f49aSdrh static int kvvfsSyncDb(sqlite3_file*, int flags); 68*7585f49aSdrh static int kvvfsSyncJrnl(sqlite3_file*, int flags); 69*7585f49aSdrh static int kvvfsFileSizeDb(sqlite3_file*, sqlite3_int64 *pSize); 70*7585f49aSdrh static int kvvfsFileSizeJrnl(sqlite3_file*, sqlite3_int64 *pSize); 71*7585f49aSdrh static int kvvfsLock(sqlite3_file*, int); 72*7585f49aSdrh static int kvvfsUnlock(sqlite3_file*, int); 73*7585f49aSdrh static int kvvfsCheckReservedLock(sqlite3_file*, int *pResOut); 74*7585f49aSdrh static int kvvfsFileControl(sqlite3_file*, int op, void *pArg); 75*7585f49aSdrh static int kvvfsSectorSize(sqlite3_file*); 76*7585f49aSdrh static int kvvfsDeviceCharacteristics(sqlite3_file*); 77*7585f49aSdrh 78*7585f49aSdrh /* 79*7585f49aSdrh ** Methods for sqlite3_vfs 80*7585f49aSdrh */ 81*7585f49aSdrh static int kvvfsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); 82*7585f49aSdrh static int kvvfsDelete(sqlite3_vfs*, const char *zName, int syncDir); 83*7585f49aSdrh static int kvvfsAccess(sqlite3_vfs*, const char *zName, int flags, int *); 84*7585f49aSdrh static int kvvfsFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); 85*7585f49aSdrh static void *kvvfsDlOpen(sqlite3_vfs*, const char *zFilename); 86*7585f49aSdrh static int kvvfsRandomness(sqlite3_vfs*, int nByte, char *zOut); 87*7585f49aSdrh static int kvvfsSleep(sqlite3_vfs*, int microseconds); 88*7585f49aSdrh static int kvvfsCurrentTime(sqlite3_vfs*, double*); 89*7585f49aSdrh static int kvvfsCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); 90*7585f49aSdrh 91*7585f49aSdrh static sqlite3_vfs kvvfs_vfs = { 92*7585f49aSdrh 1, /* iVersion */ 93*7585f49aSdrh sizeof(KVVfsFile), /* szOsFile */ 94*7585f49aSdrh 1024, /* mxPathname */ 95*7585f49aSdrh 0, /* pNext */ 96*7585f49aSdrh "kvvfs", /* zName */ 97*7585f49aSdrh 0, /* pAppData */ 98*7585f49aSdrh kvvfsOpen, /* xOpen */ 99*7585f49aSdrh kvvfsDelete, /* xDelete */ 100*7585f49aSdrh kvvfsAccess, /* xAccess */ 101*7585f49aSdrh kvvfsFullPathname, /* xFullPathname */ 102*7585f49aSdrh kvvfsDlOpen, /* xDlOpen */ 103*7585f49aSdrh 0, /* xDlError */ 104*7585f49aSdrh 0, /* xDlSym */ 105*7585f49aSdrh 0, /* xDlClose */ 106*7585f49aSdrh kvvfsRandomness, /* xRandomness */ 107*7585f49aSdrh kvvfsSleep, /* xSleep */ 108*7585f49aSdrh kvvfsCurrentTime, /* xCurrentTime */ 109*7585f49aSdrh 0, /* xGetLastError */ 110*7585f49aSdrh kvvfsCurrentTimeInt64 /* xCurrentTimeInt64 */ 111*7585f49aSdrh }; 112*7585f49aSdrh 113*7585f49aSdrh /* Methods for sqlite3_file objects referencing a database file 114*7585f49aSdrh */ 115*7585f49aSdrh static sqlite3_io_methods kvvfs_db_io_methods = { 116*7585f49aSdrh 1, /* iVersion */ 117*7585f49aSdrh kvvfsClose, /* xClose */ 118*7585f49aSdrh kvvfsReadDb, /* xRead */ 119*7585f49aSdrh kvvfsWriteDb, /* xWrite */ 120*7585f49aSdrh kvvfsTruncateDb, /* xTruncate */ 121*7585f49aSdrh kvvfsSyncDb, /* xSync */ 122*7585f49aSdrh kvvfsFileSizeDb, /* xFileSize */ 123*7585f49aSdrh kvvfsLock, /* xLock */ 124*7585f49aSdrh kvvfsUnlock, /* xUnlock */ 125*7585f49aSdrh kvvfsCheckReservedLock, /* xCheckReservedLock */ 126*7585f49aSdrh kvvfsFileControl, /* xFileControl */ 127*7585f49aSdrh kvvfsSectorSize, /* xSectorSize */ 128*7585f49aSdrh kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */ 129*7585f49aSdrh 0, /* xShmMap */ 130*7585f49aSdrh 0, /* xShmLock */ 131*7585f49aSdrh 0, /* xShmBarrier */ 132*7585f49aSdrh 0, /* xShmUnmap */ 133*7585f49aSdrh 0, /* xFetch */ 134*7585f49aSdrh 0 /* xUnfetch */ 135*7585f49aSdrh }; 136*7585f49aSdrh 137*7585f49aSdrh /* Methods for sqlite3_file objects referencing a rollback journal 138*7585f49aSdrh */ 139*7585f49aSdrh static sqlite3_io_methods kvvfs_jrnl_io_methods = { 140*7585f49aSdrh 1, /* iVersion */ 141*7585f49aSdrh kvvfsClose, /* xClose */ 142*7585f49aSdrh kvvfsReadJrnl, /* xRead */ 143*7585f49aSdrh kvvfsWriteJrnl, /* xWrite */ 144*7585f49aSdrh kvvfsTruncateJrnl, /* xTruncate */ 145*7585f49aSdrh kvvfsSyncJrnl, /* xSync */ 146*7585f49aSdrh kvvfsFileSizeJrnl, /* xFileSize */ 147*7585f49aSdrh kvvfsLock, /* xLock */ 148*7585f49aSdrh kvvfsUnlock, /* xUnlock */ 149*7585f49aSdrh kvvfsCheckReservedLock, /* xCheckReservedLock */ 150*7585f49aSdrh kvvfsFileControl, /* xFileControl */ 151*7585f49aSdrh kvvfsSectorSize, /* xSectorSize */ 152*7585f49aSdrh kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */ 153*7585f49aSdrh 0, /* xShmMap */ 154*7585f49aSdrh 0, /* xShmLock */ 155*7585f49aSdrh 0, /* xShmBarrier */ 156*7585f49aSdrh 0, /* xShmUnmap */ 157*7585f49aSdrh 0, /* xFetch */ 158*7585f49aSdrh 0 /* xUnfetch */ 159*7585f49aSdrh }; 160*7585f49aSdrh 161*7585f49aSdrh /****** Storage subsystem **************************************************/ 162*7585f49aSdrh #include <sys/types.h> 163*7585f49aSdrh #include <sys/stat.h> 164*7585f49aSdrh #include <unistd.h> 165*7585f49aSdrh 166*7585f49aSdrh /* Forward declarations for the low-level storage engine 167*7585f49aSdrh */ 168*7585f49aSdrh #define KVSTORAGE_KEY_SZ 24 169*7585f49aSdrh #define KVSTORAGE_KEY_PREFIX "kvvfs-" 170*7585f49aSdrh static int kvstorageWrite(const char*, const char *zKey, const char *zData); 171*7585f49aSdrh static int kvstorageDelete(const char*, const char *zKey); 172*7585f49aSdrh static int kvstorageRead(const char*, const char *zKey, char *zBuf, int nBuf); 173*7585f49aSdrh 174*7585f49aSdrh 175*7585f49aSdrh /* Expand the key name with an appropriate prefix and put the result 176*7585f49aSdrh ** in pStore->zKey[] 177*7585f49aSdrh */ 178*7585f49aSdrh static void kvstorageMakeKey( 179*7585f49aSdrh const char *zClass, 180*7585f49aSdrh const char *zKeyIn, 181*7585f49aSdrh char *zKeyOut 182*7585f49aSdrh ){ 183*7585f49aSdrh sqlite3_snprintf(KVSTORAGE_KEY_SZ, zKeyOut, "%s-%s", zClass, zKeyIn); 184*7585f49aSdrh } 185*7585f49aSdrh 186*7585f49aSdrh /* Write content into a key. zKey is of limited size. zData should be 187*7585f49aSdrh ** pure text. In other words, zData has already been encoded. 188*7585f49aSdrh ** 189*7585f49aSdrh ** Return the number of errors. 190*7585f49aSdrh */ 191*7585f49aSdrh static int kvstorageWrite( 192*7585f49aSdrh const char *zClass, 193*7585f49aSdrh const char *zKey, 194*7585f49aSdrh const char *zData 195*7585f49aSdrh ){ 196*7585f49aSdrh FILE *fd; 197*7585f49aSdrh char zXKey[KVSTORAGE_KEY_SZ]; 198*7585f49aSdrh kvstorageMakeKey(zClass, zKey, zXKey); 199*7585f49aSdrh fd = fopen(zXKey, "wb"); 200*7585f49aSdrh if( fd ){ 201*7585f49aSdrh SQLITE_KV_TRACE(("KVVFS-WRITE %-15s (%d) %.50s%s\n", zXKey, 202*7585f49aSdrh (int)strlen(zData), zData, 203*7585f49aSdrh strlen(zData)>50 ? "..." : "")); 204*7585f49aSdrh fputs(zData, fd); 205*7585f49aSdrh fclose(fd); 206*7585f49aSdrh return 0; 207*7585f49aSdrh }else{ 208*7585f49aSdrh return 1; 209*7585f49aSdrh } 210*7585f49aSdrh } 211*7585f49aSdrh 212*7585f49aSdrh /* Delete a key 213*7585f49aSdrh */ 214*7585f49aSdrh static int kvstorageDelete(const char *zClass, const char *zKey){ 215*7585f49aSdrh char zXKey[KVSTORAGE_KEY_SZ]; 216*7585f49aSdrh kvstorageMakeKey(zClass, zKey, zXKey); 217*7585f49aSdrh unlink(zXKey); 218*7585f49aSdrh SQLITE_KV_TRACE(("KVVFS-DELETE %-15s\n", zXKey)); 219*7585f49aSdrh return 0; 220*7585f49aSdrh } 221*7585f49aSdrh 222*7585f49aSdrh /* Read the value associated with a key and put the result in the first 223*7585f49aSdrh ** nBuf bytes of zBuf[]. The value might be truncated if zBuf is not large 224*7585f49aSdrh ** enough to hold it all. The value put into zBuf will always be zero 225*7585f49aSdrh ** terminated. 226*7585f49aSdrh ** 227*7585f49aSdrh ** Return the total number of bytes in the data, without truncation, and 228*7585f49aSdrh ** not counting the final zero terminator. Return -1 if the key does 229*7585f49aSdrh ** not exist. 230*7585f49aSdrh ** 231*7585f49aSdrh ** If nBuf==0 then this routine simply returns the size of the data without 232*7585f49aSdrh ** actually reading it. 233*7585f49aSdrh */ 234*7585f49aSdrh static int kvstorageRead( 235*7585f49aSdrh const char *zClass, 236*7585f49aSdrh const char *zKey, 237*7585f49aSdrh char *zBuf, 238*7585f49aSdrh int nBuf 239*7585f49aSdrh ){ 240*7585f49aSdrh FILE *fd; 241*7585f49aSdrh struct stat buf; 242*7585f49aSdrh char zXKey[KVSTORAGE_KEY_SZ]; 243*7585f49aSdrh kvstorageMakeKey(zClass, zKey, zXKey); 244*7585f49aSdrh if( access(zXKey, R_OK)!=0 245*7585f49aSdrh || stat(zXKey, &buf)!=0 246*7585f49aSdrh || !S_ISREG(buf.st_mode) 247*7585f49aSdrh ){ 248*7585f49aSdrh SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey)); 249*7585f49aSdrh return -1; 250*7585f49aSdrh } 251*7585f49aSdrh if( nBuf<0 ){ 252*7585f49aSdrh return (int)buf.st_size; 253*7585f49aSdrh }else if( nBuf==1 ){ 254*7585f49aSdrh zBuf[0] = 0; 255*7585f49aSdrh SQLITE_KV_TRACE(("KVVFS-READ %-15s (%d)\n", zXKey, 256*7585f49aSdrh (int)buf.st_size)); 257*7585f49aSdrh return (int)buf.st_size; 258*7585f49aSdrh } 259*7585f49aSdrh if( nBuf > buf.st_size + 1 ){ 260*7585f49aSdrh nBuf = buf.st_size + 1; 261*7585f49aSdrh } 262*7585f49aSdrh fd = fopen(zXKey, "rb"); 263*7585f49aSdrh if( fd==0 ){ 264*7585f49aSdrh SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey)); 265*7585f49aSdrh return -1; 266*7585f49aSdrh }else{ 267*7585f49aSdrh sqlite3_int64 n = fread(zBuf, 1, nBuf-1, fd); 268*7585f49aSdrh fclose(fd); 269*7585f49aSdrh zBuf[n] = 0; 270*7585f49aSdrh SQLITE_KV_TRACE(("KVVFS-READ %-15s (%lld) %.50s%s\n", zXKey, 271*7585f49aSdrh n, zBuf, n>50 ? "..." : "")); 272*7585f49aSdrh return (int)n; 273*7585f49aSdrh } 274*7585f49aSdrh } 275*7585f49aSdrh 276*7585f49aSdrh /****** Utility subroutines ************************************************/ 277*7585f49aSdrh 278*7585f49aSdrh 279*7585f49aSdrh /* 280*7585f49aSdrh ** Encode binary into the text encoded used to persist on disk. 281*7585f49aSdrh ** The output text is stored in aOut[], which must be at least 282*7585f49aSdrh ** nData+1 bytes in length. 283*7585f49aSdrh ** 284*7585f49aSdrh ** Return the actual length of the encoded text, not counting the 285*7585f49aSdrh ** zero terminator at the end. 286*7585f49aSdrh ** 287*7585f49aSdrh ** Encoding format 288*7585f49aSdrh ** --------------- 289*7585f49aSdrh ** 290*7585f49aSdrh ** * Non-zero bytes are encoded as upper-case hexadecimal 291*7585f49aSdrh ** 292*7585f49aSdrh ** * A sequence of one or more zero-bytes that are not at the 293*7585f49aSdrh ** beginning of the buffer are encoded as a little-endian 294*7585f49aSdrh ** base-26 number using a..z. "a" means 0. "b" means 1, 295*7585f49aSdrh ** "z" means 25. "ab" means 26. "ac" means 52. And so forth. 296*7585f49aSdrh ** 297*7585f49aSdrh ** * Because there is no overlap between the encoding characters 298*7585f49aSdrh ** of hexadecimal and base-26 numbers, it is always clear where 299*7585f49aSdrh ** one stops and the next begins. 300*7585f49aSdrh */ 301*7585f49aSdrh static int kvvfsEncode(const char *aData, int nData, char *aOut){ 302*7585f49aSdrh int i, j; 303*7585f49aSdrh const unsigned char *a = (const unsigned char*)aData; 304*7585f49aSdrh for(i=j=0; i<nData; i++){ 305*7585f49aSdrh unsigned char c = a[i]; 306*7585f49aSdrh if( c!=0 ){ 307*7585f49aSdrh aOut[j++] = "0123456789ABCDEF"[c>>4]; 308*7585f49aSdrh aOut[j++] = "0123456789ABCDEF"[c&0xf]; 309*7585f49aSdrh }else{ 310*7585f49aSdrh /* A sequence of 1 or more zeros is stored as a little-endian 311*7585f49aSdrh ** base-26 number using a..z as the digits. So one zero is "b". 312*7585f49aSdrh ** Two zeros is "c". 25 zeros is "z", 26 zeros is "ab", 27 is "bb", 313*7585f49aSdrh ** and so forth. 314*7585f49aSdrh */ 315*7585f49aSdrh int k; 316*7585f49aSdrh for(k=1; i+k<nData && a[i+k]==0; k++){} 317*7585f49aSdrh i += k-1; 318*7585f49aSdrh while( k>0 ){ 319*7585f49aSdrh aOut[j++] = 'a'+(k%26); 320*7585f49aSdrh k /= 26; 321*7585f49aSdrh } 322*7585f49aSdrh } 323*7585f49aSdrh } 324*7585f49aSdrh aOut[j] = 0; 325*7585f49aSdrh return j; 326*7585f49aSdrh } 327*7585f49aSdrh 328*7585f49aSdrh /* Convert hex to binary */ 329*7585f49aSdrh static char kvvfsHexToBinary(char c){ 330*7585f49aSdrh if( c>='0' && c<='9' ) return c - '0'; 331*7585f49aSdrh if( c>='A' && c<='F' ) return c - 'A' + 10; 332*7585f49aSdrh return 0; 333*7585f49aSdrh } 334*7585f49aSdrh 335*7585f49aSdrh /* 336*7585f49aSdrh ** Decode the text encoding back to binary. The binary content is 337*7585f49aSdrh ** written into pOut, which must be at least nOut bytes in length. 338*7585f49aSdrh ** 339*7585f49aSdrh ** The return value is the number of bytes actually written into aOut[]. 340*7585f49aSdrh */ 341*7585f49aSdrh static int kvvfsDecode(const char *aIn, char *aOut, int nOut){ 342*7585f49aSdrh int i, j; 343*7585f49aSdrh int c; 344*7585f49aSdrh i = 0; 345*7585f49aSdrh j = 0; 346*7585f49aSdrh while( (c = aIn[i])!=0 ){ 347*7585f49aSdrh if( c>='a' ){ 348*7585f49aSdrh int n = 0; 349*7585f49aSdrh int mult = 1; 350*7585f49aSdrh while( c>='a' && c<='z' ){ 351*7585f49aSdrh n += (c - 'a')*mult; 352*7585f49aSdrh mult *= 26; 353*7585f49aSdrh c = aIn[++i]; 354*7585f49aSdrh } 355*7585f49aSdrh if( j+n>nOut ) return -1; 356*7585f49aSdrh while( n-->0 ){ 357*7585f49aSdrh aOut[j++] = 0; 358*7585f49aSdrh } 359*7585f49aSdrh }else{ 360*7585f49aSdrh if( j>nOut ) return -1; 361*7585f49aSdrh aOut[j] = kvvfsHexToBinary(aIn[i++])<<4; 362*7585f49aSdrh aOut[j++] += kvvfsHexToBinary(aIn[i++]); 363*7585f49aSdrh } 364*7585f49aSdrh } 365*7585f49aSdrh return j; 366*7585f49aSdrh } 367*7585f49aSdrh 368*7585f49aSdrh /* 369*7585f49aSdrh ** Decode a complete journal file. Allocate space in pFile->aJrnl 370*7585f49aSdrh ** and store the decoding there. Or leave pFile->aJrnl set to NULL 371*7585f49aSdrh ** if an error is encountered. 372*7585f49aSdrh ** 373*7585f49aSdrh ** The first few characters of the text encoding will be a little-endian 374*7585f49aSdrh ** base-26 number (digits a..z) that is the total number of bytes 375*7585f49aSdrh ** in the decoded journal file image. This base-26 number is followed 376*7585f49aSdrh ** by a single space, then the encoding of the journal. The space 377*7585f49aSdrh ** separator is required to act as a terminator for the base-26 number. 378*7585f49aSdrh */ 379*7585f49aSdrh static void kvvfsDecodeJournal( 380*7585f49aSdrh KVVfsFile *pFile, /* Store decoding in pFile->aJrnl */ 381*7585f49aSdrh const char *zTxt, /* Text encoding. Zero-terminated */ 382*7585f49aSdrh int nTxt /* Bytes in zTxt, excluding zero terminator */ 383*7585f49aSdrh ){ 384*7585f49aSdrh unsigned int n; 385*7585f49aSdrh int c, i, mult; 386*7585f49aSdrh i = 0; 387*7585f49aSdrh mult = 1; 388*7585f49aSdrh while( (c = zTxt[i++])>='a' && c<='z' ){ 389*7585f49aSdrh n += (zTxt[i] - 'a')*mult; 390*7585f49aSdrh mult *= 26; 391*7585f49aSdrh } 392*7585f49aSdrh sqlite3_free(pFile->aJrnl); 393*7585f49aSdrh pFile->aJrnl = sqlite3_malloc64( n ); 394*7585f49aSdrh if( pFile->aJrnl==0 ){ 395*7585f49aSdrh pFile->nJrnl = 0; 396*7585f49aSdrh return; 397*7585f49aSdrh } 398*7585f49aSdrh pFile->nJrnl = n; 399*7585f49aSdrh n = kvvfsDecode(zTxt+i, pFile->aJrnl, pFile->nJrnl); 400*7585f49aSdrh if( n<pFile->nJrnl ){ 401*7585f49aSdrh sqlite3_free(pFile->aJrnl); 402*7585f49aSdrh pFile->aJrnl = 0; 403*7585f49aSdrh pFile->nJrnl = 0; 404*7585f49aSdrh } 405*7585f49aSdrh } 406*7585f49aSdrh 407*7585f49aSdrh /* 408*7585f49aSdrh ** Read or write the "sz" element, containing the database file size. 409*7585f49aSdrh */ 410*7585f49aSdrh static sqlite3_int64 kvvfsReadFileSize(KVVfsFile *pFile){ 411*7585f49aSdrh char zData[50]; 412*7585f49aSdrh zData[0] = 0; 413*7585f49aSdrh kvstorageRead(pFile->zClass, "sz", zData, sizeof(zData)-1); 414*7585f49aSdrh return strtoll(zData, 0, 0); 415*7585f49aSdrh } 416*7585f49aSdrh static void kvvfsWriteFileSize(KVVfsFile *pFile, sqlite3_int64 sz){ 417*7585f49aSdrh char zData[50]; 418*7585f49aSdrh sqlite3_snprintf(sizeof(zData), zData, "%lld", sz); 419*7585f49aSdrh kvstorageWrite(pFile->zClass, "sz", zData); 420*7585f49aSdrh } 421*7585f49aSdrh 422*7585f49aSdrh /****** sqlite3_io_methods methods ******************************************/ 423*7585f49aSdrh 424*7585f49aSdrh /* 425*7585f49aSdrh ** Close an kvvfs-file. 426*7585f49aSdrh */ 427*7585f49aSdrh static int kvvfsClose(sqlite3_file *pProtoFile){ 428*7585f49aSdrh KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 429*7585f49aSdrh 430*7585f49aSdrh SQLITE_KV_LOG(("xClose %s %s\n", pFile->zClass, 431*7585f49aSdrh pFile->isJournal ? "journal" : "db")); 432*7585f49aSdrh sqlite3_free(pFile->aJrnl); 433*7585f49aSdrh return SQLITE_OK; 434*7585f49aSdrh } 435*7585f49aSdrh 436*7585f49aSdrh /* 437*7585f49aSdrh ** Read from the -journal file. 438*7585f49aSdrh */ 439*7585f49aSdrh static int kvvfsReadJrnl( 440*7585f49aSdrh sqlite3_file *pProtoFile, 441*7585f49aSdrh void *zBuf, 442*7585f49aSdrh int iAmt, 443*7585f49aSdrh sqlite_int64 iOfst 444*7585f49aSdrh ){ 445*7585f49aSdrh KVVfsFile *pFile = (KVVfsFile*)pProtoFile; 446*7585f49aSdrh assert( pFile->isJournal ); 447*7585f49aSdrh SQLITE_KV_LOG(("xRead('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst)); 448*7585f49aSdrh if( pFile->aJrnl==0 ){ 449*7585f49aSdrh int szTxt = kvstorageRead(pFile->zClass, "jrnl", 0, -1); 450*7585f49aSdrh char *aTxt; 451*7585f49aSdrh if( szTxt<=4 ){ 452*7585f49aSdrh return SQLITE_IOERR; 453*7585f49aSdrh } 454*7585f49aSdrh aTxt = sqlite3_malloc64( szTxt+1 ); 455*7585f49aSdrh if( aTxt==0 ) return SQLITE_NOMEM; 456*7585f49aSdrh kvstorageRead(pFile->zClass, "jrnl", aTxt, szTxt+1); 457*7585f49aSdrh kvvfsDecodeJournal(pFile, aTxt, szTxt); 458*7585f49aSdrh sqlite3_free(aTxt); 459*7585f49aSdrh if( pFile->aJrnl==0 ) return SQLITE_IOERR; 460*7585f49aSdrh } 461*7585f49aSdrh if( iOfst+iAmt>pFile->nJrnl ){ 462*7585f49aSdrh return SQLITE_IOERR_SHORT_READ; 463*7585f49aSdrh } 464*7585f49aSdrh memcpy(zBuf, pFile->aJrnl+iOfst, iAmt); 465*7585f49aSdrh return SQLITE_OK; 466*7585f49aSdrh } 467*7585f49aSdrh 468*7585f49aSdrh /* 469*7585f49aSdrh ** Read from the database file. 470*7585f49aSdrh */ 471*7585f49aSdrh static int kvvfsReadDb( 472*7585f49aSdrh sqlite3_file *pProtoFile, 473*7585f49aSdrh void *zBuf, 474*7585f49aSdrh int iAmt, 475*7585f49aSdrh sqlite_int64 iOfst 476*7585f49aSdrh ){ 477*7585f49aSdrh KVVfsFile *pFile = (KVVfsFile*)pProtoFile; 478*7585f49aSdrh unsigned int pgno; 479*7585f49aSdrh int got, n; 480*7585f49aSdrh char zKey[30]; 481*7585f49aSdrh char aData[131073]; 482*7585f49aSdrh assert( iOfst>=0 ); 483*7585f49aSdrh assert( iAmt>=0 ); 484*7585f49aSdrh SQLITE_KV_LOG(("xRead('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst)); 485*7585f49aSdrh if( iOfst+iAmt>=512 ){ 486*7585f49aSdrh if( (iOfst % iAmt)!=0 ){ 487*7585f49aSdrh return SQLITE_IOERR_READ; 488*7585f49aSdrh } 489*7585f49aSdrh if( (iAmt & (iAmt-1))!=0 || iAmt<512 || iAmt>65536 ){ 490*7585f49aSdrh return SQLITE_IOERR_READ; 491*7585f49aSdrh } 492*7585f49aSdrh pFile->szPage = iAmt; 493*7585f49aSdrh pgno = 1 + iOfst/iAmt; 494*7585f49aSdrh }else{ 495*7585f49aSdrh pgno = 1; 496*7585f49aSdrh } 497*7585f49aSdrh sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno); 498*7585f49aSdrh got = kvstorageRead(pFile->zClass, zKey, aData, sizeof(aData)-1); 499*7585f49aSdrh if( got<0 ){ 500*7585f49aSdrh n = 0; 501*7585f49aSdrh }else{ 502*7585f49aSdrh aData[got] = 0; 503*7585f49aSdrh if( iOfst+iAmt<512 ){ 504*7585f49aSdrh n = kvvfsDecode(aData, &aData[1000], 1000); 505*7585f49aSdrh if( n>=iOfst+iAmt ){ 506*7585f49aSdrh memcpy(zBuf, &aData[1000+iOfst], iAmt); 507*7585f49aSdrh n = iAmt; 508*7585f49aSdrh }else{ 509*7585f49aSdrh n = 0; 510*7585f49aSdrh } 511*7585f49aSdrh }else{ 512*7585f49aSdrh n = kvvfsDecode(aData, zBuf, iAmt); 513*7585f49aSdrh } 514*7585f49aSdrh } 515*7585f49aSdrh if( n<iAmt ){ 516*7585f49aSdrh memset(zBuf+n, 0, iAmt-n); 517*7585f49aSdrh return SQLITE_IOERR_SHORT_READ; 518*7585f49aSdrh } 519*7585f49aSdrh return SQLITE_OK; 520*7585f49aSdrh } 521*7585f49aSdrh 522*7585f49aSdrh 523*7585f49aSdrh /* 524*7585f49aSdrh ** Write into the -journal file. 525*7585f49aSdrh */ 526*7585f49aSdrh static int kvvfsWriteJrnl( 527*7585f49aSdrh sqlite3_file *pProtoFile, 528*7585f49aSdrh const void *zBuf, 529*7585f49aSdrh int iAmt, 530*7585f49aSdrh sqlite_int64 iOfst 531*7585f49aSdrh ){ 532*7585f49aSdrh KVVfsFile *pFile = (KVVfsFile*)pProtoFile; 533*7585f49aSdrh sqlite3_int64 iEnd = iOfst+iAmt; 534*7585f49aSdrh SQLITE_KV_LOG(("xWrite('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst)); 535*7585f49aSdrh if( iEnd>=0x10000000 ) return SQLITE_FULL; 536*7585f49aSdrh if( pFile->aJrnl==0 || pFile->nJrnl<iEnd ){ 537*7585f49aSdrh char *aNew = sqlite3_realloc(pFile->aJrnl, iEnd); 538*7585f49aSdrh if( aNew==0 ){ 539*7585f49aSdrh return SQLITE_IOERR_NOMEM; 540*7585f49aSdrh } 541*7585f49aSdrh pFile->aJrnl = aNew; 542*7585f49aSdrh if( pFile->nJrnl<iOfst ){ 543*7585f49aSdrh memset(pFile->aJrnl+pFile->nJrnl, 0, iOfst-pFile->nJrnl); 544*7585f49aSdrh } 545*7585f49aSdrh pFile->nJrnl = iEnd; 546*7585f49aSdrh } 547*7585f49aSdrh memcpy(pFile->aJrnl+iOfst, zBuf, iAmt); 548*7585f49aSdrh return SQLITE_OK; 549*7585f49aSdrh } 550*7585f49aSdrh 551*7585f49aSdrh /* 552*7585f49aSdrh ** Write into the database file. 553*7585f49aSdrh */ 554*7585f49aSdrh static int kvvfsWriteDb( 555*7585f49aSdrh sqlite3_file *pProtoFile, 556*7585f49aSdrh const void *zBuf, 557*7585f49aSdrh int iAmt, 558*7585f49aSdrh sqlite_int64 iOfst 559*7585f49aSdrh ){ 560*7585f49aSdrh KVVfsFile *pFile = (KVVfsFile*)pProtoFile; 561*7585f49aSdrh unsigned int pgno; 562*7585f49aSdrh char zKey[30]; 563*7585f49aSdrh char aData[131073]; 564*7585f49aSdrh SQLITE_KV_LOG(("xWrite('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst)); 565*7585f49aSdrh assert( iAmt>=512 && iAmt<=65536 ); 566*7585f49aSdrh assert( (iAmt & (iAmt-1))==0 ); 567*7585f49aSdrh pgno = 1 + iOfst/iAmt; 568*7585f49aSdrh sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno); 569*7585f49aSdrh kvvfsEncode(zBuf, iAmt, aData); 570*7585f49aSdrh kvstorageWrite(pFile->zClass, zKey, aData); 571*7585f49aSdrh if( iOfst+iAmt > pFile->szDb ){ 572*7585f49aSdrh pFile->szDb = iOfst + iAmt; 573*7585f49aSdrh } 574*7585f49aSdrh return SQLITE_OK; 575*7585f49aSdrh } 576*7585f49aSdrh 577*7585f49aSdrh /* 578*7585f49aSdrh ** Truncate an kvvfs-file. 579*7585f49aSdrh */ 580*7585f49aSdrh static int kvvfsTruncateJrnl(sqlite3_file *pProtoFile, sqlite_int64 size){ 581*7585f49aSdrh KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 582*7585f49aSdrh SQLITE_KV_LOG(("xTruncate('%s-journal',%lld)\n", pFile->zClass, size)); 583*7585f49aSdrh assert( size==0 ); 584*7585f49aSdrh kvstorageDelete(pFile->zClass, "jrnl"); 585*7585f49aSdrh sqlite3_free(pFile->aJrnl); 586*7585f49aSdrh pFile->aJrnl = 0; 587*7585f49aSdrh pFile->nJrnl = 0; 588*7585f49aSdrh return SQLITE_OK; 589*7585f49aSdrh } 590*7585f49aSdrh static int kvvfsTruncateDb(sqlite3_file *pProtoFile, sqlite_int64 size){ 591*7585f49aSdrh KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 592*7585f49aSdrh if( pFile->szDb>size 593*7585f49aSdrh && pFile->szPage>0 594*7585f49aSdrh && (size % pFile->szPage)==0 595*7585f49aSdrh ){ 596*7585f49aSdrh char zKey[50]; 597*7585f49aSdrh unsigned int pgno, pgnoMax; 598*7585f49aSdrh SQLITE_KV_LOG(("xTruncate('%s-db',%lld)\n", pFile->zClass, size)); 599*7585f49aSdrh pgno = 1 + size/pFile->szPage; 600*7585f49aSdrh pgnoMax = 2 + pFile->szDb/pFile->szPage; 601*7585f49aSdrh while( pgno<=pgnoMax ){ 602*7585f49aSdrh sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno); 603*7585f49aSdrh kvstorageDelete(pFile->zClass, zKey); 604*7585f49aSdrh pgno++; 605*7585f49aSdrh } 606*7585f49aSdrh pFile->szDb = size; 607*7585f49aSdrh kvvfsWriteFileSize(pFile, size); 608*7585f49aSdrh return SQLITE_OK; 609*7585f49aSdrh } 610*7585f49aSdrh return SQLITE_IOERR; 611*7585f49aSdrh } 612*7585f49aSdrh 613*7585f49aSdrh /* 614*7585f49aSdrh ** Sync an kvvfs-file. 615*7585f49aSdrh */ 616*7585f49aSdrh static int kvvfsSyncJrnl(sqlite3_file *pProtoFile, int flags){ 617*7585f49aSdrh int i, n; 618*7585f49aSdrh KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 619*7585f49aSdrh char *zOut; 620*7585f49aSdrh SQLITE_KV_LOG(("xSync('%s-journal')\n", pFile->zClass)); 621*7585f49aSdrh if( pFile->nJrnl<=0 ){ 622*7585f49aSdrh return kvvfsTruncateJrnl(pProtoFile, 0); 623*7585f49aSdrh } 624*7585f49aSdrh zOut = sqlite3_malloc64( pFile->nJrnl*2 + 50 ); 625*7585f49aSdrh if( zOut==0 ){ 626*7585f49aSdrh return SQLITE_IOERR_NOMEM; 627*7585f49aSdrh } 628*7585f49aSdrh n = pFile->nJrnl; 629*7585f49aSdrh i = 0; 630*7585f49aSdrh do{ 631*7585f49aSdrh zOut[i++] = 'a' + (n%26); 632*7585f49aSdrh n /= 26; 633*7585f49aSdrh }while( n>0 ); 634*7585f49aSdrh zOut[i++] = ' '; 635*7585f49aSdrh kvvfsEncode(pFile->aJrnl, pFile->nJrnl, &zOut[i]); 636*7585f49aSdrh kvstorageWrite(pFile->zClass, "jrnl", zOut); 637*7585f49aSdrh sqlite3_free(zOut); 638*7585f49aSdrh return SQLITE_OK; 639*7585f49aSdrh } 640*7585f49aSdrh static int kvvfsSyncDb(sqlite3_file *pProtoFile, int flags){ 641*7585f49aSdrh KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 642*7585f49aSdrh SQLITE_KV_LOG(("xSync('%s-db')\n", pFile->zClass)); 643*7585f49aSdrh if( pFile->szDb>0 ){ 644*7585f49aSdrh kvvfsWriteFileSize(pFile, pFile->szDb); 645*7585f49aSdrh } 646*7585f49aSdrh return SQLITE_OK; 647*7585f49aSdrh } 648*7585f49aSdrh 649*7585f49aSdrh /* 650*7585f49aSdrh ** Return the current file-size of an kvvfs-file. 651*7585f49aSdrh */ 652*7585f49aSdrh static int kvvfsFileSizeJrnl(sqlite3_file *pProtoFile, sqlite_int64 *pSize){ 653*7585f49aSdrh KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 654*7585f49aSdrh SQLITE_KV_LOG(("xFileSize('%s-journal')\n", pFile->zClass)); 655*7585f49aSdrh *pSize = pFile->nJrnl; 656*7585f49aSdrh return SQLITE_OK; 657*7585f49aSdrh } 658*7585f49aSdrh static int kvvfsFileSizeDb(sqlite3_file *pProtoFile, sqlite_int64 *pSize){ 659*7585f49aSdrh KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 660*7585f49aSdrh SQLITE_KV_LOG(("xFileSize('%s-db')\n", pFile->zClass)); 661*7585f49aSdrh if( pFile->szDb>=0 ){ 662*7585f49aSdrh *pSize = pFile->szDb; 663*7585f49aSdrh }else{ 664*7585f49aSdrh *pSize = kvvfsReadFileSize(pFile); 665*7585f49aSdrh } 666*7585f49aSdrh return SQLITE_OK; 667*7585f49aSdrh } 668*7585f49aSdrh 669*7585f49aSdrh /* 670*7585f49aSdrh ** Lock an kvvfs-file. 671*7585f49aSdrh */ 672*7585f49aSdrh static int kvvfsLock(sqlite3_file *pProtoFile, int eLock){ 673*7585f49aSdrh KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 674*7585f49aSdrh assert( !pFile->isJournal ); 675*7585f49aSdrh SQLITE_KV_LOG(("xLock(%s,%d)\n", pFile->zClass, eLock)); 676*7585f49aSdrh 677*7585f49aSdrh if( eLock!=SQLITE_LOCK_NONE ){ 678*7585f49aSdrh pFile->szDb = kvvfsReadFileSize(pFile); 679*7585f49aSdrh } 680*7585f49aSdrh return SQLITE_OK; 681*7585f49aSdrh } 682*7585f49aSdrh 683*7585f49aSdrh /* 684*7585f49aSdrh ** Unlock an kvvfs-file. 685*7585f49aSdrh */ 686*7585f49aSdrh static int kvvfsUnlock(sqlite3_file *pProtoFile, int eLock){ 687*7585f49aSdrh KVVfsFile *pFile = (KVVfsFile *)pProtoFile; 688*7585f49aSdrh assert( !pFile->isJournal ); 689*7585f49aSdrh SQLITE_KV_LOG(("xUnlock(%s,%d)\n", pFile->zClass, eLock)); 690*7585f49aSdrh if( eLock==SQLITE_LOCK_NONE ){ 691*7585f49aSdrh pFile->szDb = -1; 692*7585f49aSdrh } 693*7585f49aSdrh return SQLITE_OK; 694*7585f49aSdrh } 695*7585f49aSdrh 696*7585f49aSdrh /* 697*7585f49aSdrh ** Check if another file-handle holds a RESERVED lock on an kvvfs-file. 698*7585f49aSdrh */ 699*7585f49aSdrh static int kvvfsCheckReservedLock(sqlite3_file *pProtoFile, int *pResOut){ 700*7585f49aSdrh SQLITE_KV_LOG(("xCheckReservedLock\n")); 701*7585f49aSdrh *pResOut = 0; 702*7585f49aSdrh return SQLITE_OK; 703*7585f49aSdrh } 704*7585f49aSdrh 705*7585f49aSdrh /* 706*7585f49aSdrh ** File control method. For custom operations on an kvvfs-file. 707*7585f49aSdrh */ 708*7585f49aSdrh static int kvvfsFileControl(sqlite3_file *pProtoFile, int op, void *pArg){ 709*7585f49aSdrh return SQLITE_NOTFOUND; 710*7585f49aSdrh } 711*7585f49aSdrh 712*7585f49aSdrh /* 713*7585f49aSdrh ** Return the sector-size in bytes for an kvvfs-file. 714*7585f49aSdrh */ 715*7585f49aSdrh static int kvvfsSectorSize(sqlite3_file *pFile){ 716*7585f49aSdrh return 512; 717*7585f49aSdrh } 718*7585f49aSdrh 719*7585f49aSdrh /* 720*7585f49aSdrh ** Return the device characteristic flags supported by an kvvfs-file. 721*7585f49aSdrh */ 722*7585f49aSdrh static int kvvfsDeviceCharacteristics(sqlite3_file *pProtoFile){ 723*7585f49aSdrh return 0; 724*7585f49aSdrh } 725*7585f49aSdrh 726*7585f49aSdrh /****** sqlite3_vfs methods *************************************************/ 727*7585f49aSdrh 728*7585f49aSdrh /* 729*7585f49aSdrh ** Open an kvvfs file handle. 730*7585f49aSdrh */ 731*7585f49aSdrh static int kvvfsOpen( 732*7585f49aSdrh sqlite3_vfs *pProtoVfs, 733*7585f49aSdrh const char *zName, 734*7585f49aSdrh sqlite3_file *pProtoFile, 735*7585f49aSdrh int flags, 736*7585f49aSdrh int *pOutFlags 737*7585f49aSdrh ){ 738*7585f49aSdrh KVVfsFile *pFile = (KVVfsFile*)pProtoFile; 739*7585f49aSdrh SQLITE_KV_LOG(("xOpen(\"%s\")\n", zName)); 740*7585f49aSdrh if( strcmp(zName, "local")==0 741*7585f49aSdrh || strcmp(zName, "session")==0 742*7585f49aSdrh ){ 743*7585f49aSdrh pFile->isJournal = 0; 744*7585f49aSdrh pFile->base.pMethods = &kvvfs_db_io_methods; 745*7585f49aSdrh }else 746*7585f49aSdrh if( strcmp(zName, "local-journal")==0 747*7585f49aSdrh || strcmp(zName, "session-journal")==0 748*7585f49aSdrh ){ 749*7585f49aSdrh pFile->isJournal = 1; 750*7585f49aSdrh pFile->base.pMethods = &kvvfs_jrnl_io_methods; 751*7585f49aSdrh }else{ 752*7585f49aSdrh return SQLITE_CANTOPEN; 753*7585f49aSdrh } 754*7585f49aSdrh if( zName[0]=='s' ){ 755*7585f49aSdrh pFile->zClass = KVSTORAGE_KEY_PREFIX "ses"; 756*7585f49aSdrh }else{ 757*7585f49aSdrh pFile->zClass = KVSTORAGE_KEY_PREFIX "loc"; 758*7585f49aSdrh } 759*7585f49aSdrh pFile->aJrnl = 0; 760*7585f49aSdrh pFile->nJrnl = 0; 761*7585f49aSdrh pFile->szPage = -1; 762*7585f49aSdrh pFile->szDb = -1; 763*7585f49aSdrh return SQLITE_OK; 764*7585f49aSdrh } 765*7585f49aSdrh 766*7585f49aSdrh /* 767*7585f49aSdrh ** Delete the file located at zPath. If the dirSync argument is true, 768*7585f49aSdrh ** ensure the file-system modifications are synced to disk before 769*7585f49aSdrh ** returning. 770*7585f49aSdrh */ 771*7585f49aSdrh static int kvvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ 772*7585f49aSdrh if( strcmp(zPath, "local-journal")==0 ){ 773*7585f49aSdrh kvstorageDelete(KVSTORAGE_KEY_PREFIX "loc", "jrnl"); 774*7585f49aSdrh }else 775*7585f49aSdrh if( strcmp(zPath, "session-journal")==0 ){ 776*7585f49aSdrh kvstorageDelete(KVSTORAGE_KEY_PREFIX "ses", "jrnl"); 777*7585f49aSdrh } 778*7585f49aSdrh return SQLITE_OK; 779*7585f49aSdrh } 780*7585f49aSdrh 781*7585f49aSdrh /* 782*7585f49aSdrh ** Test for access permissions. Return true if the requested permission 783*7585f49aSdrh ** is available, or false otherwise. 784*7585f49aSdrh */ 785*7585f49aSdrh static int kvvfsAccess( 786*7585f49aSdrh sqlite3_vfs *pProtoVfs, 787*7585f49aSdrh const char *zPath, 788*7585f49aSdrh int flags, 789*7585f49aSdrh int *pResOut 790*7585f49aSdrh ){ 791*7585f49aSdrh SQLITE_KV_LOG(("xAccess(\"%s\")\n", zPath)); 792*7585f49aSdrh if( strcmp(zPath, "local-journal")==0 ){ 793*7585f49aSdrh *pResOut = kvstorageRead(KVSTORAGE_KEY_PREFIX "loc", "jrnl", 0, -1)>0; 794*7585f49aSdrh }else 795*7585f49aSdrh if( strcmp(zPath, "session-journal")==0 ){ 796*7585f49aSdrh *pResOut = kvstorageRead(KVSTORAGE_KEY_PREFIX "ses", "jrnl", 0, -1)>0; 797*7585f49aSdrh }else 798*7585f49aSdrh if( strcmp(zPath, "local")==0 ){ 799*7585f49aSdrh *pResOut = kvstorageRead(KVSTORAGE_KEY_PREFIX "loc", "sz", 0, -1)>0; 800*7585f49aSdrh }else 801*7585f49aSdrh if( strcmp(zPath, "session")==0 ){ 802*7585f49aSdrh *pResOut = kvstorageRead(KVSTORAGE_KEY_PREFIX "ses", "sz", 0, -1)>0; 803*7585f49aSdrh }else 804*7585f49aSdrh { 805*7585f49aSdrh *pResOut = 0; 806*7585f49aSdrh } 807*7585f49aSdrh SQLITE_KV_LOG(("xAccess returns %d\n",*pResOut)); 808*7585f49aSdrh return SQLITE_OK; 809*7585f49aSdrh } 810*7585f49aSdrh 811*7585f49aSdrh /* 812*7585f49aSdrh ** Populate buffer zOut with the full canonical pathname corresponding 813*7585f49aSdrh ** to the pathname in zPath. zOut is guaranteed to point to a buffer 814*7585f49aSdrh ** of at least (INST_MAX_PATHNAME+1) bytes. 815*7585f49aSdrh */ 816*7585f49aSdrh static int kvvfsFullPathname( 817*7585f49aSdrh sqlite3_vfs *pVfs, 818*7585f49aSdrh const char *zPath, 819*7585f49aSdrh int nOut, 820*7585f49aSdrh char *zOut 821*7585f49aSdrh ){ 822*7585f49aSdrh size_t nPath = strlen(zPath); 823*7585f49aSdrh SQLITE_KV_LOG(("xFullPathname(\"%s\")\n", zPath)); 824*7585f49aSdrh if( nOut<nPath+1 ) nPath = nOut - 1; 825*7585f49aSdrh memcpy(zOut, zPath, nPath); 826*7585f49aSdrh zOut[nPath] = 0; 827*7585f49aSdrh return SQLITE_OK; 828*7585f49aSdrh } 829*7585f49aSdrh 830*7585f49aSdrh /* 831*7585f49aSdrh ** Open the dynamic library located at zPath and return a handle. 832*7585f49aSdrh */ 833*7585f49aSdrh static void *kvvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){ 834*7585f49aSdrh return 0; 835*7585f49aSdrh } 836*7585f49aSdrh 837*7585f49aSdrh /* 838*7585f49aSdrh ** Populate the buffer pointed to by zBufOut with nByte bytes of 839*7585f49aSdrh ** random data. 840*7585f49aSdrh */ 841*7585f49aSdrh static int kvvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ 842*7585f49aSdrh memset(zBufOut, 0, nByte); 843*7585f49aSdrh return nByte; 844*7585f49aSdrh } 845*7585f49aSdrh 846*7585f49aSdrh /* 847*7585f49aSdrh ** Sleep for nMicro microseconds. Return the number of microseconds 848*7585f49aSdrh ** actually slept. 849*7585f49aSdrh */ 850*7585f49aSdrh static int kvvfsSleep(sqlite3_vfs *pVfs, int nMicro){ 851*7585f49aSdrh return SQLITE_OK; 852*7585f49aSdrh } 853*7585f49aSdrh 854*7585f49aSdrh /* 855*7585f49aSdrh ** Return the current time as a Julian Day number in *pTimeOut. 856*7585f49aSdrh */ 857*7585f49aSdrh static int kvvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ 858*7585f49aSdrh *pTimeOut = 2459829.13362986; 859*7585f49aSdrh return SQLITE_OK; 860*7585f49aSdrh } 861*7585f49aSdrh static int kvvfsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){ 862*7585f49aSdrh *pTimeOut = (sqlite3_int64)(2459829.13362986*86400000.0); 863*7585f49aSdrh return SQLITE_OK; 864*7585f49aSdrh } 865*7585f49aSdrh 866*7585f49aSdrh /* 867*7585f49aSdrh ** This routine is called initialize the KV-vfs as the default VFS. 868*7585f49aSdrh */ 869*7585f49aSdrh int sqlite3_os_init(void){ 870*7585f49aSdrh return sqlite3_vfs_register(&kvvfs_vfs, 1); 871*7585f49aSdrh } 872*7585f49aSdrh int sqlite3_os_end(void){ 873*7585f49aSdrh return SQLITE_OK; 874*7585f49aSdrh } 875*7585f49aSdrh #endif /* SQLITE_OS_KV */ 876