GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/sqlitevfs.cc
Date: 2025-06-29 02:35:41
Exec Total Coverage
Lines: 123 215 57.2%
Branches: 71 180 39.4%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 *
4 * An optimized virtual file system layer for the client only. It expects to
5 * operate on immutable, valid SQlite files. Hence it can do a few
6 * optimizations. Most notably it doesn't need to know about the path of
7 * the SQlite file once opened. It works purely on the file descriptor.
8 */
9
10 #ifndef __STDC_FORMAT_MACROS
11 #define __STDC_FORMAT_MACROS
12 #endif
13
14
15 #include "sqlitevfs.h"
16
17 #include <dlfcn.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <inttypes.h>
21 #include <stdint.h>
22 #include <sys/select.h>
23 #include <sys/time.h>
24 #include <sys/types.h>
25 #include <sys/uio.h>
26 #include <unistd.h>
27
28 #include <cassert>
29 #include <climits>
30 #include <cstring>
31 #include <ctime>
32 #include <vector>
33
34 #include "cache.h"
35 #include "duplex_sqlite3.h"
36 #include "statistics.h"
37 #include "util/logging.h"
38 #include "util/platform.h"
39 #include "util/smalloc.h"
40 #include "util/string.h"
41
42 using namespace std; // NOLINT
43
44 namespace sqlite {
45
46 namespace {
47
48 const char *kVfsName = "cvmfs-readonly";
49
50 /**
51 * The private user data attached to the sqlite_vfs object.
52 */
53 struct VfsRdOnly {
54 1659 VfsRdOnly()
55 1659 : cache_mgr(NULL)
56 1659 , n_access(NULL)
57 1659 , no_open(NULL)
58 1659 , n_rand(NULL)
59 1659 , sz_rand(NULL)
60 1659 , n_read(NULL)
61 1659 , sz_read(NULL)
62 1659 , n_sleep(NULL)
63 1659 , sz_sleep(NULL)
64 1659 , n_time(NULL) { }
65 CacheManager *cache_mgr;
66 perf::Counter *n_access;
67 perf::Counter *no_open;
68 perf::Counter *n_rand;
69 perf::Counter *sz_rand;
70 perf::Counter *n_read;
71 perf::Counter *sz_read;
72 perf::Counter *n_sleep;
73 perf::Counter *sz_sleep;
74 perf::Counter *n_time;
75 };
76
77 /**
78 * This is passed to all operations once a file is opened.
79 */
80 struct VfsRdOnlyFile {
81 sqlite3_file base; // Base class. Must be first.
82 VfsRdOnly *vfs_rdonly;
83 int fd;
84 uint64_t size;
85 };
86
87 /**
88 * File descriptor mappings
89 */
90 std::vector<int> *fd_from_ = NULL;
91 std::vector<int> *fd_to_ = NULL;
92
93 } // anonymous namespace
94
95 8990 static void ApplyFdMap(VfsRdOnlyFile *pFile) {
96 8990 const unsigned N = fd_from_->size();
97
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8990 times.
8990 for (unsigned i = 0; i < N; ++i) {
98 if (pFile->fd == (*fd_from_)[i]) {
99 LogCvmfs(kLogSql, kLogDebug, "map fd %d --> %d", (*fd_from_)[i],
100 (*fd_to_)[i]);
101 pFile->fd = (*fd_to_)[i];
102 fd_from_->erase(fd_from_->begin() + i);
103 fd_to_->erase(fd_to_->begin() + i);
104 return;
105 }
106 }
107 }
108
109
110 785 static int VfsRdOnlyClose(sqlite3_file *pFile) {
111 785 VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile);
112 785 ApplyFdMap(p);
113 785 const int retval = p->vfs_rdonly->cache_mgr->Close(p->fd);
114
1/2
✓ Branch 0 taken 785 times.
✗ Branch 1 not taken.
785 if (retval == 0) {
115 785 perf::Dec(p->vfs_rdonly->no_open);
116 785 return SQLITE_OK;
117 }
118 return SQLITE_IOERR_CLOSE;
119 }
120
121
122 /**
123 * On a short read, the remaining bytes must be zero'ed.
124 * TODO(jblomer): the reads seem to be rather small. Investigate buffered read.
125 */
126 8205 static int VfsRdOnlyRead(sqlite3_file *pFile,
127 void *zBuf,
128 int iAmt,
129 sqlite_int64 iOfst) {
130 8205 VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile);
131 8205 ApplyFdMap(p);
132 8205 const ssize_t got = p->vfs_rdonly->cache_mgr->Pread(p->fd, zBuf, iAmt, iOfst);
133 8205 perf::Inc(p->vfs_rdonly->n_read);
134
1/2
✓ Branch 0 taken 8205 times.
✗ Branch 1 not taken.
8205 if (got == iAmt) {
135 8205 perf::Xadd(p->vfs_rdonly->sz_read, iAmt);
136 8205 return SQLITE_OK;
137 } else if (got < 0) {
138 return SQLITE_IOERR_READ;
139 } else {
140 perf::Xadd(p->vfs_rdonly->sz_read, got);
141 memset(reinterpret_cast<char *>(zBuf) + got, 0, iAmt - got);
142 return SQLITE_IOERR_SHORT_READ;
143 }
144 }
145
146
147 static int VfsRdOnlyWrite(sqlite3_file *pFile __attribute__((unused)),
148 const void *zBuf __attribute__((unused)),
149 int iAmt __attribute__((unused)),
150 sqlite_int64 iOfst __attribute__((unused))) {
151 return SQLITE_READONLY;
152 }
153
154
155 static int VfsRdOnlyTruncate(sqlite3_file *pFile __attribute__((unused)),
156 sqlite_int64 size __attribute__((unused))) {
157 return SQLITE_READONLY;
158 }
159
160
161 static int VfsRdOnlySync(sqlite3_file *pFile __attribute__((unused)),
162 int flags __attribute__((unused))) {
163 return SQLITE_OK;
164 }
165
166
167 785 static int VfsRdOnlyFileSize(sqlite3_file *pFile, sqlite_int64 *pSize) {
168 785 VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile);
169 785 *pSize = p->size;
170 785 return SQLITE_OK;
171 }
172
173
174 785 static int VfsRdOnlyLock(sqlite3_file *p __attribute__((unused)),
175 int level __attribute__((unused))) {
176 785 return SQLITE_OK;
177 }
178
179
180 785 static int VfsRdOnlyUnlock(sqlite3_file *p __attribute__((unused)),
181 int level __attribute__((unused))) {
182 785 return SQLITE_OK;
183 }
184
185
186 static int VfsRdOnlyCheckReservedLock(sqlite3_file *p __attribute__((unused)),
187 int *pResOut) {
188 *pResOut = 0;
189 return SQLITE_OK;
190 }
191
192
193 /**
194 * No xFileControl() verbs are implemented by this VFS.
195 */
196 3925 static int VfsRdOnlyFileControl(sqlite3_file *p __attribute__((unused)),
197 int op __attribute__((unused)),
198 void *pArg __attribute__((unused))) {
199 3925 return SQLITE_NOTFOUND;
200 }
201
202
203 /**
204 * A good unit of bytes to read at once. But probably only used for writes.
205 */
206 785 static int VfsRdOnlySectorSize(sqlite3_file *p __attribute__((unused))) {
207 785 return 4096;
208 }
209
210
211 /**
212 * Only relevant for writing.
213 */
214 2355 static int VfsRdOnlyDeviceCharacteristics(sqlite3_file *p
215 __attribute__((unused))) {
216 2355 return 0;
217 }
218
219
220 /**
221 * Supports only read-only opens. The "file name" has to be in the form of
222 * '@<file descriptor>', where file descriptor is usable by the cache manager.
223 */
224 785 static int VfsRdOnlyOpen(sqlite3_vfs *vfs,
225 const char *zName,
226 sqlite3_file *pFile,
227 int flags,
228 int *pOutFlags) {
229 static const sqlite3_io_methods io_methods = {1, // iVersion
230 VfsRdOnlyClose,
231 VfsRdOnlyRead,
232 VfsRdOnlyWrite,
233 VfsRdOnlyTruncate,
234 VfsRdOnlySync,
235 VfsRdOnlyFileSize,
236 VfsRdOnlyLock,
237 VfsRdOnlyUnlock,
238 VfsRdOnlyCheckReservedLock,
239 VfsRdOnlyFileControl,
240 VfsRdOnlySectorSize,
241 VfsRdOnlyDeviceCharacteristics};
242
243 785 VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile);
244 785 CacheManager *cache_mgr = reinterpret_cast<VfsRdOnly *>(vfs->pAppData)
245 ->cache_mgr;
246 // Prevent xClose from being called in case of errors
247 785 p->base.pMethods = NULL;
248
249
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 785 times.
785 if (flags & SQLITE_OPEN_READWRITE)
250 return SQLITE_IOERR;
251
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 785 times.
785 if (flags & SQLITE_OPEN_DELETEONCLOSE)
252 return SQLITE_IOERR;
253
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 785 times.
785 if (flags & SQLITE_OPEN_EXCLUSIVE)
254 return SQLITE_IOERR;
255
256
2/4
✓ Branch 0 taken 785 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 785 times.
✗ Branch 3 not taken.
785 assert(zName && (zName[0] == '@'));
257
2/4
✓ Branch 2 taken 785 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 785 times.
✗ Branch 6 not taken.
785 p->fd = String2Int64(string(&zName[1]));
258
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 785 times.
785 if (p->fd < 0)
259 return SQLITE_IOERR;
260 785 const int64_t size = cache_mgr->GetSize(p->fd);
261
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 785 times.
785 if (size < 0) {
262 cache_mgr->Close(p->fd);
263 p->fd = -1;
264 return SQLITE_IOERR_FSTAT;
265 }
266
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 785 times.
785 if (cache_mgr->Readahead(p->fd) != 0) {
267 cache_mgr->Close(p->fd);
268 p->fd = -1;
269 return SQLITE_IOERR;
270 }
271 785 p->size = static_cast<uint64_t>(size);
272
1/2
✓ Branch 0 taken 785 times.
✗ Branch 1 not taken.
785 if (pOutFlags)
273 785 *pOutFlags = flags;
274 785 p->vfs_rdonly = reinterpret_cast<VfsRdOnly *>(vfs->pAppData);
275 785 p->base.pMethods = &io_methods;
276 785 perf::Inc(p->vfs_rdonly->no_open);
277 785 LogCvmfs(kLogSql, kLogDebug, "open sqlite3 catalog on fd %d, size %" PRIu64,
278 p->fd, p->size);
279 785 return SQLITE_OK;
280 }
281
282
283 static int VfsRdOnlyDelete(sqlite3_vfs * __attribute__((unused)),
284 const char *zName __attribute__((unused)),
285 int syncDir __attribute__((unused))) {
286 return SQLITE_IOERR_DELETE;
287 }
288
289
290 /**
291 * Cvmfs r/o file catalogs cannot have a write-ahead log or a journal.
292 */
293 1570 static int VfsRdOnlyAccess(sqlite3_vfs *vfs,
294 const char *zPath,
295 int flags,
296 int *pResOut) {
297
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1570 times.
1570 if (flags == SQLITE_ACCESS_READWRITE) {
298 *pResOut = 0;
299 return SQLITE_OK;
300 }
301
22/50
✓ Branch 2 taken 1570 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1570 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1570 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 785 times.
✓ Branch 12 taken 785 times.
✓ Branch 15 taken 785 times.
✗ Branch 16 not taken.
✓ Branch 19 taken 785 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 785 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 785 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 785 times.
✓ Branch 27 taken 785 times.
✓ Branch 29 taken 785 times.
✓ Branch 30 taken 785 times.
✓ Branch 32 taken 785 times.
✓ Branch 33 taken 785 times.
✓ Branch 35 taken 785 times.
✓ Branch 36 taken 785 times.
✓ Branch 38 taken 1570 times.
✗ Branch 39 not taken.
✓ Branch 41 taken 1570 times.
✗ Branch 42 not taken.
✓ Branch 44 taken 1570 times.
✗ Branch 45 not taken.
✓ Branch 47 taken 1570 times.
✗ Branch 48 not taken.
✓ Branch 50 taken 1570 times.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
1570 if (HasSuffix(zPath, "-wal", false) || HasSuffix(zPath, "-journal", false)) {
302 1570 *pResOut = 0;
303 1570 return SQLITE_OK;
304 }
305
306 // This VFS deals with file descriptors, we know the files are there
307 *pResOut = 0;
308 perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_access);
309 return SQLITE_OK;
310 }
311
312
313 /**
314 * Since the path is never stored, there is no need to produce a full path.
315 */
316 785 int VfsRdOnlyFullPathname(sqlite3_vfs *vfs __attribute__((unused)),
317 const char *zPath,
318 int nOut,
319 char *zOut) {
320 785 zOut[nOut - 1] = '\0';
321 785 sqlite3_snprintf(nOut, zOut, "%s", zPath);
322 785 return SQLITE_OK;
323 }
324
325
326 /**
327 * Taken from unixRandomness
328 */
329 static int VfsRdOnlyRandomness(sqlite3_vfs *vfs, int nBuf, char *zBuf) {
330 assert(static_cast<size_t>(nBuf) >= (sizeof(time_t) + sizeof(int)));
331 perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_rand);
332 memset(zBuf, 0, nBuf);
333 pid_t randomnessPid = getpid();
334 int fd, got;
335 fd = open("/dev/urandom", O_RDONLY, 0);
336 if (fd < 0) {
337 time_t t;
338 time(&t);
339 memcpy(zBuf, &t, sizeof(t));
340 memcpy(&zBuf[sizeof(t)], &randomnessPid, sizeof(randomnessPid));
341 assert(sizeof(t) + sizeof(randomnessPid) <= static_cast<size_t>(nBuf));
342 nBuf = sizeof(t) + sizeof(randomnessPid);
343 } else {
344 do {
345 got = read(fd, zBuf, nBuf);
346 } while (got < 0 && errno == EINTR);
347 close(fd);
348 }
349 perf::Xadd(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->sz_rand, nBuf);
350 return nBuf;
351 }
352
353
354 /**
355 * Like SafeSleepMs, avoid conflict with the ALARM signal.
356 */
357 static int VfsRdOnlySleep(sqlite3_vfs *vfs, int microseconds) {
358 struct timeval wait_for;
359 wait_for.tv_sec = microseconds / (1000 * 1000);
360 wait_for.tv_usec = microseconds % (1000 * 1000);
361 select(0, NULL, NULL, NULL, &wait_for);
362 perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_sleep);
363 perf::Xadd(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->sz_sleep,
364 microseconds);
365 return microseconds;
366 }
367
368
369 /**
370 * Taken from unixCurrentTimeInt64()
371 */
372 static int VfsRdOnlyCurrentTimeInt64(sqlite3_vfs *vfs, sqlite3_int64 *piNow) {
373 static const sqlite3_int64 unixEpoch = 24405875 * (sqlite3_int64)8640000;
374 int rc = SQLITE_OK;
375 struct timeval sNow;
376 if (gettimeofday(&sNow, 0) == 0) {
377 *piNow = unixEpoch + 1000 * (sqlite3_int64)sNow.tv_sec
378 + sNow.tv_usec / 1000;
379 perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_time);
380 } else {
381 rc = SQLITE_ERROR;
382 }
383 return rc;
384 }
385
386
387 /**
388 * Taken from unixCurrentTime
389 */
390 static int VfsRdOnlyCurrentTime(sqlite3_vfs *vfs, double *prNow) {
391 sqlite3_int64 i = 0;
392 const int rc = VfsRdOnlyCurrentTimeInt64(vfs, &i);
393 *prNow = i / 86400000.0;
394 return rc;
395 }
396
397
398 /**
399 * So far unused by sqlite.
400 */
401 static int VfsRdOnlyGetLastError(sqlite3_vfs *vfs __attribute__((unused)),
402 int not_used1 __attribute__((unused)),
403 char *not_used2 __attribute__((unused))) {
404 return 0;
405 }
406
407
408 /**
409 * Can only be registered once.
410 */
411 1659 bool RegisterVfsRdOnly(CacheManager *cache_mgr,
412 perf::Statistics *statistics,
413 const VfsOptions options) {
414 1659 fd_from_ = new std::vector<int>();
415 1659 fd_to_ = new std::vector<int>();
416
417 sqlite3_vfs *vfs = reinterpret_cast<sqlite3_vfs *>(
418 1659 smalloc(sizeof(sqlite3_vfs)));
419 1659 memset(vfs, 0, sizeof(sqlite3_vfs));
420 1659 VfsRdOnly *vfs_rdonly = new VfsRdOnly();
421
422 1659 vfs->iVersion = 2;
423 1659 vfs->szOsFile = sizeof(VfsRdOnlyFile);
424 1659 vfs->mxPathname = PATH_MAX;
425 1659 vfs->zName = kVfsName;
426 1659 vfs->pAppData = vfs_rdonly;
427 1659 vfs->xOpen = VfsRdOnlyOpen;
428 1659 vfs->xDelete = VfsRdOnlyDelete;
429 1659 vfs->xAccess = VfsRdOnlyAccess;
430 1659 vfs->xFullPathname = VfsRdOnlyFullPathname;
431 1659 vfs->xDlOpen = NULL;
432 1659 vfs->xDlError = NULL;
433 1659 vfs->xDlSym = NULL;
434 1659 vfs->xDlClose = NULL;
435 1659 vfs->xRandomness = VfsRdOnlyRandomness;
436 1659 vfs->xSleep = VfsRdOnlySleep;
437 1659 vfs->xCurrentTime = VfsRdOnlyCurrentTime;
438 1659 vfs->xGetLastError = VfsRdOnlyGetLastError;
439 1659 vfs->xCurrentTimeInt64 = VfsRdOnlyCurrentTimeInt64;
440
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1659 times.
1659 assert(vfs->zName);
441
442 1659 const int retval = sqlite3_vfs_register(vfs, options == kVfsOptDefault);
443
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1659 times.
1659 if (retval != SQLITE_OK) {
444 free(const_cast<char *>(vfs->zName));
445 delete vfs_rdonly;
446 free(vfs);
447 return false;
448 }
449
450 1659 vfs_rdonly->cache_mgr = cache_mgr;
451
3/6
✓ Branch 2 taken 1659 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1659 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1659 times.
✗ Branch 10 not taken.
1659 vfs_rdonly->n_access = statistics->Register(
452 "sqlite.n_access", "overall number of access() calls");
453
3/6
✓ Branch 2 taken 1659 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1659 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1659 times.
✗ Branch 10 not taken.
1659 vfs_rdonly->no_open = statistics->Register("sqlite.no_open",
454 "currently open sqlite files");
455
3/6
✓ Branch 2 taken 1659 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1659 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1659 times.
✗ Branch 10 not taken.
1659 vfs_rdonly->n_rand = statistics->Register("sqlite.n_rand",
456 "overall number of random() calls");
457
3/6
✓ Branch 2 taken 1659 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1659 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1659 times.
✗ Branch 10 not taken.
1659 vfs_rdonly->sz_rand = statistics->Register("sqlite.sz_rand",
458 "overall number of random bytes");
459
3/6
✓ Branch 2 taken 1659 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1659 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1659 times.
✗ Branch 10 not taken.
1659 vfs_rdonly->n_read = statistics->Register("sqlite.n_read",
460 "overall number of read() calls");
461
3/6
✓ Branch 2 taken 1659 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1659 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1659 times.
✗ Branch 10 not taken.
1659 vfs_rdonly->sz_read = statistics->Register("sqlite.sz_read",
462 "overall bytes read()");
463
3/6
✓ Branch 2 taken 1659 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1659 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1659 times.
✗ Branch 10 not taken.
1659 vfs_rdonly->n_sleep = statistics->Register("sqlite.n_sleep",
464 "overall number of sleep() calls");
465
3/6
✓ Branch 2 taken 1659 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1659 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1659 times.
✗ Branch 10 not taken.
1659 vfs_rdonly->sz_sleep = statistics->Register("sqlite.sz_sleep",
466 "overall microseconds slept");
467
3/6
✓ Branch 2 taken 1659 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1659 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1659 times.
✗ Branch 10 not taken.
1659 vfs_rdonly->n_time = statistics->Register("sqlite.n_time",
468 "overall number of time() calls");
469
470 1659 return true;
471 }
472
473
474 /**
475 * If the file system was the default VFS, another default VFS is selected by
476 * SQlite randomly.
477 */
478 1656 bool UnregisterVfsRdOnly() {
479 1656 sqlite3_vfs *vfs = sqlite3_vfs_find(kVfsName);
480
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1656 times.
1656 if (vfs == NULL)
481 return false;
482 1656 const int retval = sqlite3_vfs_unregister(vfs);
483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1656 times.
1656 if (retval != SQLITE_OK)
484 return false;
485
486
1/2
✓ Branch 0 taken 1656 times.
✗ Branch 1 not taken.
1656 delete reinterpret_cast<VfsRdOnly *>(vfs->pAppData);
487 1656 free(vfs);
488
489
1/2
✓ Branch 0 taken 1656 times.
✗ Branch 1 not taken.
1656 delete fd_from_;
490
1/2
✓ Branch 0 taken 1656 times.
✗ Branch 1 not taken.
1656 delete fd_to_;
491 1656 fd_from_ = NULL;
492 1656 fd_to_ = NULL;
493
494 1656 return true;
495 }
496
497 void RegisterFdMapping(int from, int to) {
498 fd_from_->push_back(from);
499 fd_to_->push_back(to);
500 }
501
502 void ReplaceCacheManager(CacheManager *new_cache_mgr) {
503 sqlite3_vfs *vfs = sqlite3_vfs_find(kVfsName);
504 if (vfs == NULL)
505 return;
506 static_cast<VfsRdOnly *>(vfs->pAppData)->cache_mgr = new_cache_mgr;
507 }
508
509 } // namespace sqlite
510