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